Spark AR is Facebook’s free AR creation platform that enables users to create interactive AR experiences for Facebook and Instagram. More than 400,000 creators in 190 countries have used Spark AR to create their own AR creations

Since the software requires no coding knowledge to use, anyone can now lead the world by creating the next crazy viral Instagram AR effects with little experience in the AR world.

Specialized AR filter designers can cost anywhere from $1,000 to $30,000.

Zoom recorder with gestures

Access Placer

To scale and rotate the speaker, we will use the Placer object. The reason we need to do this is because we already used the base object in the zoom animation, and if we use it again here, it will overwrite that animation.

Add the following code to find the placer:

Promise.all([
    sceneRoot.findFirst('base_jnt'), // Existing code
    sceneRoot.findFirst('speaker_left_jnt'), // Existing code
    sceneRoot.findFirst('speaker_right_jnt'), // Existing code
    sceneRoot.findFirst('planeTracker0'), // Existing code
    sceneRoot.findFirst('placer')
 ])
 .then(function(objects) {
    const base = objects[0]; // Existing code
    const speakerLeft = objects[1]; // Existing code
    const speakerRight = objects[2]; // Existing code
    const planeTracker = objects[3]; // Existing code
    const placer = objects[4];
Copy the code

Now that we have access to the placer, we can store a transformation that refers to it (just as we did with the underlying object) to update the scale and rotation.

Script code

const placerTransform = placer.transform;
Copy the code

Subscribe to Pinch Gesture

To scale the recorder, we’re going to subscribe to the Pinch gesture, where you gesture closer and further away with two fingers.

The following code uses a slightly different subscription method that also allows us to capture signal values while detecting gestures.

Script code

 TouchGestures.onPinch().subscribeWithSnapshot( {

 }, function (gesture, snapshot) {});Copy the code

The subscribeWithSnapshot() method allows us to capture additional “snapshot” values that we need to pass to the callback callback update scale.

Passing snapshot values

The values we want to pass to the callback function when scaling the gesture are the current x, Y, and Z scaling values of the placerTransform. The reason we need to do this is that we want to change the scaling (increase or decrease depending on the gesture) based on the current scale.

Add snapshot code to the subscription function

TouchGestures.onPinch().subscribeWithSnapshot( { // Existing code
    'lastScaleX' : placerTransform.scaleX,
    'lastScaleY' : placerTransform.scaleY,
    'lastScaleZ' : placerTransform.scaleZ 
   }, function (gesture, snapshot) { // Existing code
 }); // Existing code
Copy the code

A snapshot is a dictionary of signal values that can be accessed by name in the callback function.

Scaling of placer

The current scale value passed from the snapshot can now be used in the callback function to scale the placer in conjunction with the scale value obtained from the scale gesture.

Add scaling code to the callback function:

 TouchGestures.onPinch().subscribeWithSnapshot( { // Existing code
     'lastScaleX' : placerTransform.scaleX, // Existing code
     'lastScaleY' : placerTransform.scaleY, // Existing code
     'lastScaleZ' : placerTransform.scaleZ // Existing code
 }, function (gesture, snapshot) { // Existing code
     placerTransform.scaleX = gesture.scale.mul(snapshot.lastScaleX);
     placerTransform.scaleY = gesture.scale.mul(snapshot.lastScaleY);
     placerTransform.scaleZ = gesture.scale.mul(snapshot.lastScaleZ);
 }); // Existing code
Copy the code

Multiply the snapshot value by PinchGesture’s scale property to get the desired scaling effect.

The script code is as follows

const Animation = require('Animation');
 const Scene = require('Scene');
 const TouchGestures = require('TouchGestures');
 
 const sceneRoot = Scene.root;
 
 Promise.all([
     sceneRoot.findFirst('base_jnt'),
     sceneRoot.findFirst('speaker_left_jnt'),
     sceneRoot.findFirst('speaker_right_jnt'),
     sceneRoot.findFirst('planeTracker0'),
     sceneRoot.findFirst('placer')
 ])
 .then(function(objects) {
     const base = objects[0];
     const speakerLeft = objects[1];
     const speakerRight = objects[2];
     const planeTracker = objects[3];
     const placer = objects[4];
     
     const baseDriverParameters = {
         durationMilliseconds: 400.loopCount: Infinity.mirror: true
     };
 
     const baseDriver = Animation.timeDriver(baseDriverParameters);
     baseDriver.start();
 
     const baseSampler = Animation.samplers.easeInQuint(0.9.1);
 
     const baseAnimation = Animation.animate(baseDriver,baseSampler);
 
     const baseTransform = base.transform;
 
     baseTransform.scaleX = baseAnimation;
     baseTransform.scaleY = baseAnimation;
     baseTransform.scaleZ = baseAnimation;
     
     const speakerDriverParameters = {
         durationMilliseconds: 200.loopCount: Infinity.mirror: true
     };
 
     const speakerDriver = Animation.timeDriver(speakerDriverParameters);
     speakerDriver.start();
 
     const speakerSampler = Animation.samplers.easeOutElastic(0.7.0.85);
 
     const speakerAnimation = Animation.animate(speakerDriver,speakerSampler);
     
     const speakerLeftTransform = speakerLeft.transform;
 
     speakerLeftTransform.scaleX = speakerAnimation;
     speakerLeftTransform.scaleY = speakerAnimation;
     speakerLeftTransform.scaleZ = speakerAnimation;
 
     const speakerRightTransform = speakerRight.transform;
 
     speakerRightTransform.scaleX = speakerAnimation;
     speakerRightTransform.scaleY = speakerAnimation;
     speakerRightTransform.scaleZ = speakerAnimation;
     
     TouchGestures.onPan().subscribe(function(gesture) {
         planeTracker.trackPoint(gesture.location, gesture.state);
     });
     
     const placerTransform = placer.transform;
     
     TouchGestures.onPinch().subscribeWithSnapshot( {
         'lastScaleX' : placerTransform.scaleX,
         'lastScaleY' : placerTransform.scaleY,
         'lastScaleZ' : placerTransform.scaleZ 
     }, function (gesture, snapshot) {
         placerTransform.scaleX = gesture.scale.mul(snapshot.lastScaleX);
         placerTransform.scaleY = gesture.scale.mul(snapshot.lastScaleY);
         placerTransform.scaleZ = gesture.scale.mul(snapshot.lastScaleZ);
     });
 });
Copy the code

Save your script and return to Spark AR Studio

Send the project to the app of your choice and you can now scale the recorder on your device by using two fingers and the Pinch gesture.

Rotate recorder by gesture

Subscribe rotation gesture

To spin the recorder, we will subscribe to the spin gesture, which is a gesture that uses two fingers to rotate each other.

Add code to the script

TouchGestures.onRotate().subscribeWithSnapshot( {
     'lastRotationY' : placerTransform.rotationY,
  }, function (gesture, snapshot) {
     const correctRotation = gesture.rotation.mul(-1);
     placerTransform.rotationY = correctRotation.add(snapshot.lastRotationY);
 });
Copy the code

We pass the y rotation value of the placerTransform (the axis we’ll rotate around) to the callback function using subscribeWithSnapshot().

In the callback function, we multiply RotateGesture’s rotation by -1, and then add it to the placerTransform to rotate the recorder. We multiplied the gesture rotation by -1 to ensure that the rotation occurred in the right direction.

const Animation = require('Animation');
 const Scene = require('Scene');
 const TouchGestures = require('TouchGestures');
 
 const sceneRoot = Scene.root;
 
 Promise.all([
     sceneRoot.findFirst('base_jnt'),
     sceneRoot.findFirst('speaker_left_jnt'),
     sceneRoot.findFirst('speaker_right_jnt'),
     sceneRoot.findFirst('planeTracker0'),
     sceneRoot.findFirst('placer')
 ])
 .then(function(objects) {
     const base = objects[0];
     const speakerLeft = objects[1];
     const speakerRight = objects[2];
     const planeTracker = objects[3];
     const placer = objects[4];
     
     const baseDriverParameters = {
         durationMilliseconds: 400.loopCount: Infinity.mirror: true
     };
 
     const baseDriver = Animation.timeDriver(baseDriverParameters);
     baseDriver.start();
 
     const baseSampler = Animation.samplers.easeInQuint(0.9.1);
 
     const baseAnimation = Animation.animate(baseDriver,baseSampler);
 
     const baseTransform = base.transform;
 
     baseTransform.scaleX = baseAnimation;
     baseTransform.scaleY = baseAnimation;
     baseTransform.scaleZ = baseAnimation;
     
     const speakerDriverParameters = {
         durationMilliseconds: 200.loopCount: Infinity.mirror: true
     };
 
     const speakerDriver = Animation.timeDriver(speakerDriverParameters);
     speakerDriver.start();
 
     const speakerSampler = Animation.samplers.easeOutElastic(0.7.0.85);
 
     const speakerAnimation = Animation.animate(speakerDriver,speakerSampler);
     
     const speakerLeftTransform = speakerLeft.transform;
 
     speakerLeftTransform.scaleX = speakerAnimation;
     speakerLeftTransform.scaleY = speakerAnimation;
     speakerLeftTransform.scaleZ = speakerAnimation;
 
     const speakerRightTransform = speakerRight.transform;
 
     speakerRightTransform.scaleX = speakerAnimation;
     speakerRightTransform.scaleY = speakerAnimation;
     speakerRightTransform.scaleZ = speakerAnimation;
     
     TouchGestures.onPan().subscribe(function(gesture) {
         planeTracker.trackPoint(gesture.location, gesture.state);
     });
     
     const placerTransform = placer.transform;
     
     TouchGestures.onPinch().subscribeWithSnapshot( {
         'lastScaleX' : placerTransform.scaleX,
         'lastScaleY' : placerTransform.scaleY,
         'lastScaleZ' : placerTransform.scaleZ 
     }, function (gesture, snapshot) {
         placerTransform.scaleX = gesture.scale.mul(snapshot.lastScaleX);
         placerTransform.scaleY = gesture.scale.mul(snapshot.lastScaleY);
         placerTransform.scaleZ = gesture.scale.mul(snapshot.lastScaleZ);
     });
     
     TouchGestures.onRotate().subscribeWithSnapshot( {
         'lastRotationY' : placerTransform.rotationY,
     }, function (gesture, snapshot) {
         const correctRotation = gesture.rotation.mul(-1);
         placerTransform.rotationY = correctRotation.add(snapshot.lastRotationY);
     });
 });
Copy the code

Save your script and return to Spark AR Studio

Send the item to the app of your choice and you can now rotate the recorder by using two fingers and the spin gesture.