# Project export: SnapChest

This document was generated by HackStack to give an AI agent context about a hackathon project. Sections are labeled with their provenance; content marked as truncated was cut to keep this document small.

## Project metadata

- Hackathon: Cal Hacks 11.0
- Tagline: Find treasure using the Spectacles + haptic smartphone feedback!
- Devpost: https://devpost.com/software/spectacles-treasure-hunt
- GitHub: https://github.com/dawoon19/treasure-hunt-spectacles
- Result: winner (Snap: Dream it. Build it.)
- Team: 3 GitHub contributor(s) — Daniel He (15 commits), Daniel Won (11 commits), jhu9998 (5 commits)

## Devpost submission (written by the team)

### Inspiration

Open-world AR applications like Pokemon Go that bring AR into everyday life and the outdoors were major inspirations for this project. Additionally, in thinking about how to integrate smartphones with Spectacles, we found inspiration in video games like Phasmophobia's EMP sensors that react more strongly in the presence of ghosts or The Legend of Zelda: Skyward Sword that contained an in-game tracking functionality that pulsates more strongly when facing the direction of and walking closer to a target.

### What it does

This game integrates the Spectacles gear and smartphones together by allowing users to leverage the gyroscopic, haptic, and tactile functionalities of phones to control or receive input about their AR environment. In the game, users have to track down randomly placed treasure chests in their surrounding environment by using their phone as a sensor that begins vibrating when the user is facing a treasure and enters stronger modes of haptic feedback as users get closer to the treasure spots. These chests come in three types: monetary, puzzle, and challenge. Monetary chests immediately give users in-game rewards. Puzzle chests engage users in a single-player mini-game that may require cognitive or physical activity. Finally, challenge chests similarly engage users in activities not necessarily games, and a stretch goal for multiplayers was that if multiple users were near a spot that another user found a treasure in, the other n users could challenge the treasure finder in a n vs. 1 duel, with the winner(s) taking the rewards.

### How we built it

Once we figured out our direction for the project, we built a user flow architecture in Figma to brainstorm the game design for our application (link), and we also visualized how to implement the system for integrating phone haptic feedback with the spectacles depending on distance and directional conditions. From there, we each took on specific aspects of the user flow architecture to primarily work on: (1) the treasure detection mechanism, (2) spawning the treasure once the user entered within a short distance from the target, and (3) the content of the treasure chests (i.e. rewards or activities). Nearly everything was done using in-house libraries, assets, and the GenAI suite within Snap's Lens Studio.

### Challenges we ran into

As we were working with Spectacles for the first time (compounded with internet problems), we initially encountered technical issues with setting up our development environment and linking the Spectacles for debugging. Due to limited documentation and forums since it is limited-access technology, we had to do a lot of trial-and-error and guessing to figure out how to get our code to work, but luckily, Snap's documentation provided templates to work off of and the Snap staff was able to provide technical assistance to guide us in the right direction. Additionally, given one Spectacle to work with, parallelizing our development work was quite challenging as we had to integrate everything onto one computer while dealing with merge conflicts between our code.

### Accomplishments we're proud of

In a short span of time, we were able to successfully build a game that provides a unique immersive experience! We've come across and solved errors that didn't have solutions on the internet. For a couple of members of our team, this sparks a newfound interest in the AR space.

### What we learned

This was our first time working with Lens Studio and it's unanimously been a smooth and great software to work with. For the experienced members on our team, it's been a rewarding experience to make an AR application using JS/TS instead of C# which is the standard language used in Unity.

### What's next

We're excited to push this app forward by adding more locations for treasures, implementing a point system, and also a voice agent integration that provides feedback based on where you're going so you won't get bored on your journey! If Spectacles would be made available to the general public, a multiplayer functionality would definitely gain a lot of traction and we're looking forward to the future!

## README (from the GitHub repository)

No README available.

## Detected evidence (automated analysis)

Indexed codebase: 194 recognized source files, 1364 KB.
- JavaScript (language) — detected in the code
- TypeScript (language) — detected in the code

## Codebase structure (from repository index)

### Files (120 of 1040)

```
.DS_Store
Spectacles/.gitattributes
Spectacles/.gitignore
Spectacles/Assets/Audience Applause SFX Pack/Audience Applause SFX Pack Resources/cheering_long.mp3.meta
Spectacles/Assets/Audience Applause SFX Pack/Audience Applause SFX Pack Resources/cheering_mid.mp3.meta
Spectacles/Assets/Audience Applause SFX Pack/Audience Applause SFX Pack Resources/cheering_short.mp3.meta
Spectacles/Assets/Audience Applause SFX Pack/AudienceApplauseSFX__PLACE_IN_OBJECTS_PANEL.prefab
Spectacles/Assets/Audience Applause SFX Pack/AudienceApplauseSFX__PLACE_IN_OBJECTS_PANEL.prefab.meta
Spectacles/Assets/Base.png.meta
Spectacles/Assets/BaseballBat/.hidden/baseball.ss_graph
Spectacles/Assets/BaseballBat/.hidden/baseball.ss_graph.meta
Spectacles/Assets/BaseballBat/BaseballBat.prefab
Spectacles/Assets/BaseballBat/BaseballBat.prefab.meta
Spectacles/Assets/BaseballBat/Bitmoji Sports Pack Resourcres/BitmojiSports__PLACE_IN_OBJECTS_PANEL.prefab
Spectacles/Assets/BaseballBat/Bitmoji Sports Pack Resourcres/BitmojiSports__PLACE_IN_OBJECTS_PANEL.prefab.meta
Spectacles/Assets/BaseballBat/Bitmoji Sports Pack Resourcres/Meshes/bat_baseball/Material/bat_baseball.mat
Spectacles/Assets/BaseballBat/Bitmoji Sports Pack Resourcres/Meshes/bat_baseball/Material/bat_baseball.mat.meta
Spectacles/Assets/BaseballBat/Bitmoji Sports Pack Resourcres/Meshes/bat_baseball/Meshes/C_bat_GEO.mesh
Spectacles/Assets/BaseballBat/Bitmoji Sports Pack Resourcres/Meshes/bat_baseball/Meshes/C_bat_GEO.mesh.meta
Spectacles/Assets/BaseballBat/Bitmoji Sports Pack Resourcres/Textures/bat_baseball_color.png.meta
Spectacles/Assets/Basket/Basket.prefab
Spectacles/Assets/Basket/Basket.prefab.meta
Spectacles/Assets/Basket/Generative 3D Component.lsc
Spectacles/Assets/Basket/Generative 3D Component.lsc.meta
Spectacles/Assets/Chain Physics/.hidden/Graph Matte Shadow.ss_graph
Spectacles/Assets/Chain Physics/.hidden/Graph Matte Shadow.ss_graph.meta
Spectacles/Assets/Chain Physics/.hidden/Graph Occluder.ss_graph
Spectacles/Assets/Chain Physics/.hidden/Graph Occluder.ss_graph.meta
Spectacles/Assets/Chain Physics/.hidden/leaf_blue.ss_graph
Spectacles/Assets/Chain Physics/.hidden/leaf_blue.ss_graph.meta
Spectacles/Assets/Chain Physics/Chain Physics Resources/Face Mesh.facemesh
Spectacles/Assets/Chain Physics/Chain Physics Resources/Face Mesh.facemesh.meta
Spectacles/Assets/Chain Physics/Chain Physics Resources/Materials/Graph Matte Shadow.mat
Spectacles/Assets/Chain Physics/Chain Physics Resources/Materials/Graph Matte Shadow.mat.meta
Spectacles/Assets/Chain Physics/Chain Physics Resources/Materials/Graph Occluder.mat
Spectacles/Assets/Chain Physics/Chain Physics Resources/Materials/Graph Occluder.mat.meta
Spectacles/Assets/Chain Physics/Chain Physics Resources/Materials/leaf_blue.mat
Spectacles/Assets/Chain Physics/Chain Physics Resources/Materials/leaf_blue.mat.meta
Spectacles/Assets/Chain Physics/Chain Physics Resources/Materials/leaf_green.mat
Spectacles/Assets/Chain Physics/Chain Physics Resources/Materials/leaf_green.mat.meta
Spectacles/Assets/Chain Physics/Chain Physics Resources/Materials/leaf_purple.mat
Spectacles/Assets/Chain Physics/Chain Physics Resources/Materials/leaf_purple.mat.meta
Spectacles/Assets/Chain Physics/Chain Physics Resources/Models/Leaf/Meshes/Leaf.mesh
Spectacles/Assets/Chain Physics/Chain Physics Resources/Models/Leaf/Meshes/Leaf.mesh.meta
Spectacles/Assets/Chain Physics/Chain Physics Resources/Scripts/ChainController.js
Spectacles/Assets/Chain Physics/Chain Physics Resources/Scripts/ChainController.js.meta
Spectacles/Assets/Chain Physics/Chain Physics Resources/Scripts/JSMathLibraryModule.js
Spectacles/Assets/Chain Physics/Chain Physics Resources/Scripts/JSMathLibraryModule.js.meta
Spectacles/Assets/Chain Physics/Chain Physics Resources/Scripts/PositionBasedDynamicsModule.js
Spectacles/Assets/Chain Physics/Chain Physics Resources/Scripts/PositionBasedDynamicsModule.js.meta
Spectacles/Assets/Chain Physics/Chain Physics Resources/Textures/leaf_base.png.meta
Spectacles/Assets/Chain Physics/Chain Physics Resources/Textures/leaf_normal.png.meta
Spectacles/Assets/Chain Physics/Chain Physics Resources/Textures/leaf_prams.png.meta
Spectacles/Assets/Chain Physics/Chain_Physics__PUT_UNDER_MAIN_CAM.prefab
Spectacles/Assets/Chain Physics/Chain_Physics__PUT_UNDER_MAIN_CAM.prefab.meta
Spectacles/Assets/ChallengeChestOnSpawn.prefab
Spectacles/Assets/ChallengeChestOnSpawn.prefab.meta
Spectacles/Assets/Device Camera Texture.deviceCameraTexture
Spectacles/Assets/Device Camera Texture.deviceCameraTexture.meta
Spectacles/Assets/Dice Roll/.hidden/Dice Material [REPLACE ME].ss_graph
Spectacles/Assets/Dice Roll/.hidden/Dice Material [REPLACE ME].ss_graph.meta
Spectacles/Assets/Dice Roll/.hidden/Floor.ss_graph
Spectacles/Assets/Dice Roll/.hidden/Floor.ss_graph.meta
Spectacles/Assets/Dice Roll/.hidden/Numbers [EDIT].ss_graph
Spectacles/Assets/Dice Roll/.hidden/Numbers [EDIT].ss_graph.meta
Spectacles/Assets/Dice Roll/.hidden/SpriteGraphPreset.lsmat.mat
Spectacles/Assets/Dice Roll/.hidden/SpriteGraphPreset.lsmat.mat.meta
Spectacles/Assets/Dice Roll/.hidden/SpriteGraphPreset1.lsmat.ss_graph
Spectacles/Assets/Dice Roll/.hidden/SpriteGraphPreset1.lsmat.ss_graph.meta
Spectacles/Assets/Dice Roll/Dice Roll Resources/Info Card [DELETE_ME]/Textures/info_card.png.meta
Spectacles/Assets/Dice Roll/Dice Roll Resources/Materials/Dice Material [REPLACE ME].mat
Spectacles/Assets/Dice Roll/Dice Roll Resources/Materials/Dice Material [REPLACE ME].mat.meta
Spectacles/Assets/Dice Roll/Dice Roll Resources/Materials/Floor.mat
Spectacles/Assets/Dice Roll/Dice Roll Resources/Materials/Floor.mat.meta
Spectacles/Assets/Dice Roll/Dice Roll Resources/Materials/Numbers [EDIT].mat
Spectacles/Assets/Dice Roll/Dice Roll Resources/Materials/Numbers [EDIT].mat.meta
Spectacles/Assets/Dice Roll/Dice Roll Resources/Materials/Numbers_x10 [EDIT].mat
Spectacles/Assets/Dice Roll/Dice Roll Resources/Materials/Numbers_x10 [EDIT].mat.meta
Spectacles/Assets/Dice Roll/Dice Roll Resources/Meshes/10_dice/Meshes/d_10.mesh
Spectacles/Assets/Dice Roll/Dice Roll Resources/Meshes/10_dice/Meshes/d_10.mesh.meta
Spectacles/Assets/Dice Roll/Dice Roll Resources/Meshes/12_dice/Meshes/d_12.mesh
Spectacles/Assets/Dice Roll/Dice Roll Resources/Meshes/12_dice/Meshes/d_12.mesh.meta
Spectacles/Assets/Dice Roll/Dice Roll Resources/Meshes/20_dice/Meshes/d_20.mesh
Spectacles/Assets/Dice Roll/Dice Roll Resources/Meshes/20_dice/Meshes/d_20.mesh.meta
Spectacles/Assets/Dice Roll/Dice Roll Resources/Meshes/4_dice/Meshes/d_4.mesh
Spectacles/Assets/Dice Roll/Dice Roll Resources/Meshes/4_dice/Meshes/d_4.mesh.meta
Spectacles/Assets/Dice Roll/Dice Roll Resources/Meshes/6_dice/Meshes/d_6_numbers.mesh
Spectacles/Assets/Dice Roll/Dice Roll Resources/Meshes/6_dice/Meshes/d_6_numbers.mesh.meta
Spectacles/Assets/Dice Roll/Dice Roll Resources/Meshes/8_dice/Meshes/d_8.mesh
Spectacles/Assets/Dice Roll/Dice Roll Resources/Meshes/8_dice/Meshes/d_8.mesh.meta
Spectacles/Assets/Dice Roll/Dice Roll Resources/Meshes/Box.mesh
Spectacles/Assets/Dice Roll/Dice Roll Resources/Meshes/Box.mesh.meta
Spectacles/Assets/Dice Roll/Dice Roll Resources/Physics Matter [EDIT].matter
Spectacles/Assets/Dice Roll/Dice Roll Resources/Physics Matter [EDIT].matter.meta
Spectacles/Assets/Dice Roll/Dice Roll Resources/Scripts/CallbackExample.js
Spectacles/Assets/Dice Roll/Dice Roll Resources/Scripts/CallbackExample.js.meta
Spectacles/Assets/Dice Roll/Dice Roll Resources/Scripts/DiceController.js
Spectacles/Assets/Dice Roll/Dice Roll Resources/Scripts/DiceController.js.meta
Spectacles/Assets/Dice Roll/Dice Roll Resources/Textures/Noise_Electro.jpg.meta
Spectacles/Assets/Dice Roll/Dice Roll Resources/Textures/Normal.png.meta
Spectacles/Assets/Dice Roll/Dice Roll Resources/Textures/numbers_font_1.png.meta
Spectacles/Assets/Dice Roll/Dice Roll Resources/Textures/numbers_x10.png.meta
Spectacles/Assets/Dice Roll/Dice_Roll_PLACE_IN_OBJECTS_PANEL.prefab
Spectacles/Assets/Dice Roll/Dice_Roll_PLACE_IN_OBJECTS_PANEL.prefab.meta
Spectacles/Assets/Echopark.hdr
Spectacles/Assets/Echopark.hdr.meta
Spectacles/Assets/GameChestOnSpawn.prefab
Spectacles/Assets/GameChestOnSpawn.prefab.meta
Spectacles/Assets/GameManager.ts
Spectacles/Assets/GameManager.ts.meta
Spectacles/Assets/GPU Particles Effects Pack.lspkg
Spectacles/Assets/GPU Particles Effects Pack.lspkg.meta
Spectacles/Assets/Map Component.lsc
Spectacles/Assets/Map Component.lsc.meta
Spectacles/Assets/MaterialParams.png.meta
Spectacles/Assets/MoneyChestOnSpawn.prefab
Spectacles/Assets/MoneyChestOnSpawn.prefab.meta
Spectacles/Assets/Normal.png.meta
Spectacles/Assets/PBR 1.mat
Spectacles/Assets/PBR 1.mat.meta
[920 more files omitted for size]
```

### Dependencies

No dependency index available.

### Recent commits (newest first)

- demo builds
- try fix
- try stuff
- Merge remote-tracking branch 'origin/game-manager'
- test
- Created game manager
- finished minigames
- Completed Spawning the Treasure on Surfaces
- Added motion controller for panda
- added assets for baseball bat and basket
- try fix stuffs
- Reapply "voice tests"
- Revert "voice tests"
- added minigame
- Merge branch 'main' of https://github.com/dawoon19/treasure-hunt-spectacles
- voice tests
- added catching minigame
- added catching minigame
- remove unneeded objects
- treasure bound

## Key source files (fetched from GitHub, selected and truncated for size)

### Spectacles/Assets/PinataGame.ts

```typescript
const MotionControllerModule = require('LensStudio:MotionControllerModule');

@component
export class NewScript extends BaseScriptComponent {

    private controller;

  @input
  childObject: SceneObject;

  @input 
  childCollider: ColliderComponent;

  private health;

    onAwake() {
        var options = MotionController.Options.create();
        options.motionType = MotionController.MotionType.SixDoF;
        this.controller = MotionControllerModule.getController(options);

        // this.controller = MotionControllerHelper.controller;
        this.health = 100;
        // this.childCollider.onCollisionEnter.add(this.handleCollision.bind(this));
        this.childCollider.onOverlapStay.add(this.handleCollision.bind(this));
    }

    handleCollision() {
        var request = MotionController.HapticRequest.create()
        request.hapticFeedback = MotionController.HapticFeedback.VibrationHigh
        request.duration = 1.0
        this.controller.invokeHaptic(request)

        print(this.health);
        this.health -= 20;
        if (this.health <= 0) { 
            this.childObject.enabled = false;
        }

    }
}

```

### Spectacles/Assets/SpawnTreasureInWorld.ts

```typescript
// import required modules
const WorldQueryModule = require('LensStudio:WorldQueryModule');
const SIK = require('SpectaclesInteractionKit/SIK').SIK;
const InteractorTriggerType =
  require('SpectaclesInteractionKit/Core/Interactor/Interactor').InteractorTriggerType;
const InteractorInputType =
  require('SpectaclesInteractionKit/Core/Interactor/Interactor').InteractorInputType;
const EPSILON = 0.01;

@component
export class NewScript extends BaseScriptComponent {
    private spawnPosition;

    @input
    cameraObject: SceneObject;
    @input
    targetObject: SceneObject;

    @input
    filterEnabled: boolean;    

    @input
    treasureBound: SceneObject;
    
    @input
    found: boolean;
    
    onAwake() {
        this.found = false;
        this.chooseTreasurePosition();

        
        
       
        //this.spawnPosition = new vec3(0, 0, -300);
        //this.targetObject.getTransform().setWorldPosition(this.spawnPosition);
        
        // create update event
        this.createEvent("UpdateEvent").bind(this.onUpdate.bind(this));
    }
    
    chooseTreasurePosition() {
        // Randomize the x and z coordinate ()  
        var frontOrBackX;
        if (Math.random() < 0.5) {
            frontOrBackX = -1;
        } else {
            frontOrBackX = 1;
        }
        var frontOrBackZ;
        if (Math.random() < 0.5) {
            frontOrBackZ = -1;
        } else {
            frontOrBackZ = 1;
        }
        const distX = MathUtils.randomRange(200, 600);
        const distZ = MathUtils.randomRange(200, 600);
        const finalPosition = new vec3(distX * frontOrBackX, -50, distZ * frontOrBackZ);
        this.targetObject.getTransform().setWorldPosition(finalPosition);
        this.spawnPosition = finalPosition;
        this.setTreasureBound();
    }

    setTreasureBound() {
        this.treasureBound.getTransform().setWorldPosition(this.spawnPosition);
    }
    
    getTreasurePosition() {
        return this.spawnPosition;
    }
    
    setTreasurePosition(pos) {
        this.targetObject.getTransform().setWorldPosition(pos);
    }
    
    onUpdate() {
        // print(this.cameraObject.getTransform().getWorldPosition().distance(
        //      this.targetObject.getTransform().getWorldPosition()  ));
        var distanceToTreasure = this.cameraObject.getTransform().getWorldPosition().distance(this.targetObject.getTransform().getWorldPosition());
        //print(distanceToTreasure);   
        if (distanceToTreasure < 200) {
            this.targetObject.enabled = true;
            //Added this line for game manager tracking
            this.found = true;
            //Activate the 2nd and 3rd treasure chests
            
        }
    }
    
    getTaskCompleted() {
        return this.found;
    }
}

```

### Spectacles/Assets/GameManager.ts

```typescript
import {NewScript} from './SpawnTreasureInWorld';
import {MotionControllerHelper} from './testspec/MotionControllerHelper';
import {MotionControllerHelper2} from './testspec/MotionControllerHelper2';
import {MotionControllerHelper3} from './testspec/MotionControllerHelper3';

@component
export class GameManager extends BaseScriptComponent {
    //private minigameId:Number;

    @input
    moneyChest: SceneObject;     
    @input
    pinata: SceneObject;
    @input
    minigame: SceneObject;
    @input
    detector: SceneObject;
    @input
    spawnScript: NewScript;
    @input
    detectorScript: MotionControllerHelper;
    @input
    pinataScript: MotionControllerHelper2;  //Pinata script
    @input
    minigameScript: MotionControllerHelper3; //Minigame
    
    private moneyChestCompleted = false;
    private pinataCompleted = false;
    private minigameCompleted = false;
    
    private moneyChestChecked = false;
    private pinataChestChecked = false;
    private minigameChestChecked = false;
    
    onAwake() {    
        //var store = global.persistentStorageSystem.store;
        //if (store.getInt("gameID") > 0) {
        //    this.minigameId = store.getInt("gameID");
        //}  else {
        //    this.minigameId = -1; // not in game/challenge mode;
        //}
        
        //print(this.spawnScript.completed);
        this.spawnScript.targetObject = this.moneyChest;
        this.spawnScript.chooseTreasurePosition();
        this.createEvent("UpdateEvent").bind(this.onUpdate.bind(this));
    }

    onUpdate() {
        this.moneyChestCompleted = this.spawnScript.getTaskCompleted();
        if (this.minigame.enabled) {
            this.minigameCompleted =  this.minigameScript.getTaskCompleted3();
        } else {
            this.minigameCompleted = false;
        }
        if (this.pinata.enabled) {
            this.pinataCompleted = this.pinataScript.getTaskCompleted2();
        } else {
            this.pinataCompleted = false;
        }
        
        
        // if (this.moneyChestCompleted && !this.moneyChestChecked) {
        //     this.spawnScript.found = false;
        //     this.spawnScript.targetObject = this.minigame;
        //     this.spawnScript.chooseTreasurePosition();
        //     this.moneyChestChecked = true;
            
        // }
        // else if (this.minigameCompleted && !this.minigameChestChecked) {
        //     this.spawnScript.found = false;
        //     this.spawnScript.targetObject = this.pinata;
        //     this.spawnScript.chooseTreasurePosition();
        //     this.minigameChestChecked = true;
        //     this.detector.enabled = true;
        // }
        // else if (this.pinataCompleted && !this.pinataChestChecked) {
        //     this.pinataChestChecked = true;
        //     this.detector.enabled = true;
        // }
        
        
        
    }
}

```

### Spectacles/Assets/TestSpawnObjectInWorld.ts

```typescript
// import required modules
const WorldQueryModule = require('LensStudio:WorldQueryModule');
const SIK = require('SpectaclesInteractionKit/SIK').SIK;
const InteractorTriggerType =
  require('SpectaclesInteractionKit/Core/Interactor/Interactor').InteractorTriggerType;
const InteractorInputType =
  require('SpectaclesInteractionKit/Core/Interactor/Interactor').InteractorInputType;
const EPSILON = 0.01;

@component
export class NewScript extends BaseScriptComponent {
  private primaryInteractor;
  private hitTestSession;
  private transform: Transform;

  @input
  targetObject: SceneObject;

  @input
  filterEnabled: boolean;

  onAwake() {
    // create new hit session
    this.hitTestSession = this.createHitTestSession(this.filterEnabled);
    if (!this.sceneObject) {
      print('Please set Target Object input');
      return;
    }
    this.transform = this.targetObject.getTransform();
    // disable target object when surface is not detected
    this.targetObject.enabled = false;
    // create update event
    this.createEvent('UpdateEvent').bind(this.onUpdate.bind(this));
  }

  createHitTestSession(filterEnabled) {
    // create hit test session with options
    var options = HitTestSessionOptions.create();
    options.filter = filterEnabled;

    var session = WorldQueryModule.createHitTestSessionWithOptions(options);
    return session;
  }

  onHitTestResult(results) {
    if (results === null) {
      this.targetObject.enabled = false;
    } else {
      this.targetObject.enabled = true;
      // get hit information
      const hitPosition = results.position;
      const hitNormal = results.normal;

      //identifying the direction the object should look at based on the normal of the hit location.

      var lookDirection;
      if (1 - Math.abs(hitNormal.normalize().dot(vec3.up())) < EPSILON) {
        lookDirection = vec3.forward();
      } else {
        lookDirection = hitNormal.cross(vec3.up());
      }

      const toRotation = quat.lookAt(lookDirection, hitNormal);
      //set position and rotation
      this.targetObject.getTransform().setWorldPosition(hitPosition);
      this.targetObject.getTransform().setWorldRotation(toRotation);

      if (
        this.primaryInteractor.previousTrigger !== InteractorTriggerType.None &&
        this.primaryInteractor.currentTrigger === InteractorTriggerType.None
      ) {
        // Called when a trigger ends
        // Copy the plane/axis object
        this.sceneObject.copyWholeHierarchy(this.targetObject);
      }
    }
  }

  onUpdate() {
    this.primaryInteractor =
      SIK.InteractionManager.getTargetingInteractors().shift();

    if (
      this.primaryInteractor &&
      this.primaryInteractor.isActive() &&
      this.primaryInteractor.isTargeting()
    ) {
      const rayStartOffset = new vec3(
        this.primaryInteractor.startPoint.x,
        this.primaryInteractor.startPoint.y,
        this.primaryInteractor.startPoint.z + 30
      );
      const rayStart = rayStartOffset;
      const rayEnd = this.primaryInteractor.endPoint;

      this.hitTestSession.hitTest(
        rayStart,
        rayEnd,
        this.onHitTestResult.bind(this)
      );
    } else {
      this.targetObject.enabled = false;
    }
  }
}
```

### Spectacles/Assets/Red Panda/MotionControllerHelperPanda.ts

```typescript
const MotionControllerModule = require('LensStudio:MotionControllerModule');

@component
export class NewScript extends BaseScriptComponent {
  private transform;
  private controller;
  @input
  pandaObj: SceneObject;
  @input
  frameObj: SceneObject;
  onAwake() {
    var options = MotionController.Options.create();
    options.motionType = MotionController.MotionType.SixDoF;
    this.controller = MotionControllerModule.getController(options);

    this.transform = this.sceneObject.getTransform();
    this.controller.onTransformEvent.add(this.updateTransform.bind(this));
  }

  updateTransform(position, rotation) {
    this.transform.setWorldPosition(position);
    this.transform.setWorldRotation(rotation);
    if (this.transform.up.y > 0.95) {
      this.pandaObj.enabled = true;
      this.frameObj.enabled = true;
    } else {
      this.pandaObj.enabled = false;
      this.frameObj.enabled = false;
    }
  }
}

```

### Spectacles/Assets/TreasureChestAssets/TreasureChestAnimation.ts

```typescript
// import {} from ''
@component
export class SpawnTreasureAnimation extends BaseScriptComponent {

    @input
    sparklesPrefab: ObjectPrefab;
    @input 
    trailEffectPrefab: ObjectPrefab;
    @input
    chestPrefab: ObjectPrefab;

    @input
    audio: AudioComponent;

    // eventData: UpdateEvent,
    createObjectsFromPrefab( trailEffectPrefab:ObjectPrefab, chestPrefab:ObjectPrefab, sparklesPrefab:ObjectPrefab) {
        if (trailEffectPrefab && chestPrefab) {
            var trailEffect = trailEffectPrefab.instantiate(this.getSceneObject());
            var chest = chestPrefab.instantiate(this.getSceneObject());
            var sparkles = sparklesPrefab.instantiate(this.getSceneObject());
            print("we did it.")
        }
    }

    onAwake() {
        print(this.trailEffectPrefab);
        print(this.chestPrefab);
        this.createObjectsFromPrefab(this.trailEffectPrefab, this.chestPrefab, this.sparklesPrefab)
        // var delayedEvent:DelayedCallbackEvent = this.createEvent("DelayedCallbackEvent");
        // delayedEvent.bind(this.createObjectsFromPrefab.bind(this, this.trailEffectPrefab,this.chestPrefab));
        // delayedEvent.reset(2);
        this.audio.play(1);
        print("delay started");
    }

    
}
```

### Spectacles/Assets/SpectaclesInteractionKit/SIK.ts

```typescript
import { InteractionManager as InteractionManagerProvider } from './Core/InteractionManager/InteractionManager';
import { CursorControllerProvider } from './Providers/CursorControllerProvider/CursorControllerProvider';
import { HandInputData as HandInputDataProvider } from './Providers/HandInputData/HandInputData';
import { InteractionConfigurationProvider } from './Providers/InteractionConfigurationProvider/InteractionConfigurationProvider';
import SIKLogLevelProvider from './Providers/InteractionConfigurationProvider/SIKLogLevelProvider';
import { MobileInputData as MobileInputDataProvider } from './Providers/MobileInputData/MobileInputData';

export interface SIKAPI {
  SIKLogLevelProvider: SIKLogLevelProvider
  InteractionConfiguration: InteractionConfigurationProvider
  HandInputData: HandInputDataProvider
  MobileInputData: MobileInputDataProvider
  InteractionManager: InteractionManagerProvider
  CursorController: CursorControllerProvider
}

export const SIK: SIKAPI = new Proxy({},
    {
        get: (target, prop: keyof SIKAPI) => {
            switch (prop) {
                case 'SIKLogLevelProvider':
                    return SIKLogLevelProvider.getInstance();
                case 'InteractionConfiguration':
                    return InteractionConfigurationProvider.getInstance();
                case 'HandInputData':
                    return HandInputDataProvider.getInstance();
                case 'MobileInputData':
                    return MobileInputDataProvider.getInstance();
                case 'InteractionManager':
                    return InteractionManagerProvider.getInstance();
                case 'CursorController':
                    return CursorControllerProvider.getInstance();
                default:
                    throw new Error(`Property ${String(prop)} does not exist on SIK API`);
            }
        },
    }) as SIKAPI;

```

### Spectacles/Assets/testspec/MotionControllerHelper3.ts

```typescript
const MotionControllerModule = require('LensStudio:MotionControllerModule');

declare global {
  var catchPoints: number;
}

@component
export class MotionControllerHelper3 extends BaseScriptComponent {
  private transform;
  public controller;

  @input
  childObject: SceneObject;

  @input 
  childCollider: ColliderComponent;

  @input
  catchingGame : SceneObject;

    @input 
    trailEffectPrefab: ObjectPrefab;
    
        @input
  detector: SceneObject;

    @input
    audio: AudioComponent;

    @input
    textUI: Text;

    private completed: boolean;

  onAwake() {

        this.detector.enabled = false;
    this.completed = false;
    globalThis.completed3 = false;
    globalThis.catchPoints = 0;
    var options = MotionController.Options.create();
    options.motionType = MotionController.MotionType.SixDoF;
    this.controller = MotionControllerModule.getController(options);

    this.transform = this.sceneObject.getTransform();
    this.controller.onTransformEvent.add(this.updateTransform.bind(this));

    this.childCollider.onOverlapEnter.add(function (e) {
      print("hello")
      print(globalThis.catchPoints)
      globalThis.catchPoints += 1;
  });

    this.createEvent("UpdateEvent").bind(this.onUpdate.bind(this));
  }

  getTaskCompleted3() {
    return this.completed;
}

  updateTransform(position, rotation) {
    this.transform.setWorldPosition(position);
    this.transform.setWorldRotation(rotation);
  }

  createObjectsFromPrefab( trailEffectPrefab:ObjectPrefab) {
    if (trailEffectPrefab) {
        var trailEffect = trailEffectPrefab.instantiate(this.getSceneObject());
        print("we did it.")
    }
}

  onUpdate() {
    this.textUI.text = "Points: " + globalThis.catchPoints.toString();
    if (globalThis.catchPoints >= 10 && !globalThis.completed3) {
      globalThis.completed3 = true;
      this.childObject.enabled = false;
      this.catchingGame.enabled = false;
      this.createObjectsFromPrefab(this.trailEffectPrefab);
      this.audio.play(1);
    }
  }
    

}

//   testFunc() {
//     this.controller.isControllerAvailable;
//   }

```

### Spectacles/Assets/testspec/MotionControllerHelper2.ts

```typescript
const MotionControllerModule = require('LensStudio:MotionControllerModule');

@component
export class MotionControllerHelper2 extends BaseScriptComponent {
  private transform;
  public controller;

  @input
  childObject: SceneObject;

  @input 
  childCollider: ColliderComponent;

  @input
  targetObj: SceneObject;

    @input 
    trailEffectPrefab: ObjectPrefab;

    @input
    audio: AudioComponent;
    
    @input
  detector: SceneObject;

  private pinataHealth;
  private taskCompleted = false;

  onAwake() {
        this.detector.enabled = false;
    this.pinataHealth = 300;
    var options = MotionController.Options.create();
    options.motionType = MotionController.MotionType.SixDoF;
    this.controller = MotionControllerModule.getController(options);

    this.transform = this.sceneObject.getTransform();
    this.controller.onTransformEvent.add(this.updateTransform.bind(this));

    // make sure its only detected for "layer 2" objects
    this.childCollider.onCollisionExit.add(this.detectCollision.bind(this));
  }
  getTaskCompleted2() {
    return this.taskCompleted;
}

  updateTransform(position, rotation) {
    this.transform.setWorldPosition(position);
    this.transform.setWorldRotation(rotation);
  }

  createObjectsFromPrefab( trailEffectPrefab:ObjectPrefab) {
    if (trailEffectPrefab) {
        var trailEffect = trailEffectPrefab.instantiate(this.getSceneObject());
        print("we did it.")
    }
}

  detectCollision(){
    if (this.childObject.enabled) {
        var request = MotionController.HapticRequest.create()

        request.hapticFeedback = MotionController.HapticFeedback.VibrationHigh
        request.duration = 1.0
        this.controller.invokeHaptic(request)

        print(this.pinataHealth);
        this.pinataHealth -= 20;
        if (this.pinataHealth <= 0) { 
            this.targetObj.enabled = false
            this.createObjectsFromPrefab(this.trailEffectPrefab)
            globalThis.completed2 = true;
            this.audio.play(1);
        }
    }
  }
    

}

//   testFunc() {
//     this.controller.isControllerAvailable;
//   }

```

### Spectacles/Assets/testspec/MotionControllerHelper.ts

```typescript
const MotionControllerModule = require('LensStudio:MotionControllerModule');

@component
export class MotionControllerHelper extends BaseScriptComponent {
  private transform;
  public controller;

  @input
  childObject: SceneObject;

  @input 
  childCollider: ColliderComponent;

  @input
  treasureBound: SceneObject;

  onAwake() {
    var options = MotionController.Options.create();
    options.motionType = MotionController.MotionType.SixDoF;
    this.controller = MotionControllerModule.getController(options);

    this.transform = this.sceneObject.getTransform();
    this.controller.onTransformEvent.add(this.updateTransform.bind(this));

    // this.controller.onTouchEvent.add(this.onTouchEvent.bind(this));

    // make sure its only detected for "layer 1" objects
    this.childCollider.onOverlapStay.add(this.detectCollision.bind(this));
  }

  updateTransform(position, rotation) {
    this.transform.setWorldPosition(position);
    this.transform.setWorldRotation(rotation);
  }

  onTouchEvent(normalizedPosition, touchId, timestampMs, phase) {
    if (phase != MotionController.TouchPhase.Began) {
        return
    }
    this.childObject.enabled = !this.childObject.enabled;
    if (this.childObject.enabled) {
        var request = MotionController.HapticRequest.create()
        request.hapticFeedback = MotionController.HapticFeedback.VibrationHigh
        
        request.duration = 1.0
        this.controller.invokeHaptic(request)
    }

    }

  detectCollision(){
    if (this.childObject.enabled) {
        var distToBox = this.transform.getWorldPosition().distance(this.treasureBound.getTransform().getWorldPosition());

        var request = MotionController.HapticRequest.create()

        if (distToBox < 300) { 
          request.hapticFeedback = MotionController.HapticFeedback.VibrationHigh
          request.duration = 0.1
          this.controller.invokeHaptic(request)
        } else if (distToBox < 600){
          request.hapticFeedback = MotionController.HapticFeedback.VibrationMedium
          request.duration = 0.1
          this.controller.invokeHaptic(request)
        } else {
          request.hapticFeedback = MotionController.HapticFeedback.VibrationLow
          request.duration = 0.1
          this.controller.invokeHaptic(request)
        } 

        // request.hapticFeedback = MotionController.HapticFeedback.VibrationLow
        
        // request.duration = 0.1
        // this.controller.invokeHaptic(request)
    }
  }
}

//   testFunc() {
//     this.controller.isControllerAvailable;
//   }

```

[180 more indexed source files omitted to keep this export small. The full file list is in the Codebase structure section above.]