Hide and show object depending on mouth open in Spark AR scripting - spark-ar-studio

I'm using a script in Spark AR Studio to try to show and hide a lightbulb on top of a person's head. The bulb hides with bulb.hidden I have tried bulb.visible unsuccessfully. Any Ideas? Code below:
(async function () {
Scene.root.findFirst('Sphere').then(bulb => {
// bulb.hidden = FaceTracking.face(0).mouth.openness
bulb.hidden = true
bulb.visible = FaceTracking.face(0).mouth.openness.gt(0.3);
})

bulb.hidden = true //this will show the bulb
bulb.hidden = false //this will hide the bulb
bulb.visible //this is not a valid property
What you want is:
bulb.hidden = FaceTracking.face(0).mouth.openness.gt(0.3);
This will set bulb.hidden to true when the mouth openness is greater than .3, ie when mouth is open, hide the bulb.
Alternatively, if you want to show the bulb when the mouth is open, use lt (less than) instead of gt (greater than) like this:
bulb.hidden = FaceTracking.face(0).mouth.openness.lt(0.3);
See the ScalarSignal documentation pages for info on what all the different methods available for ScalarSignals... there are many:
https://sparkar.facebook.com/ar-studio/learn/reference/classes/reactivemodule.scalarsignal/

Related

How to represent a state machine with HTML elements?

On a web page I wish to display an element which depends on the state of some JavaScript. State like in a state machine. Currently the possible states are these (but I may add more):
input: display some input elements for the user to set. The user can click a button to start some JavaScript processing and move to the working state.
working: display a progress bar informing the user that the script is running. The user can cancel the computation (moving back to the input state) or the computation can end (moving to either the result or error state).
result: display the computation result. The user can go back to input with a button.
error: display the error. The user can go back to input with a button.
The JavaScript part is ready and working, but I'm unsure how to do this in HTML + CSS.
Current solution and its issue
Currently I've been doing it with classes: I set a class to a common ancestor element with the same name of the state and I display the right elements based on it. Something like this:
const parent=document.querySelector("#parent");
let timer=null;
function input(){
parent.classList.remove("working","result","error");
parent.classList.add("input");
}
function run(){
parent.classList.remove("input");
parent.classList.add("working");
timer=setTimeout(result,1500)
}
function stop(){
clearTimeout(timer);
input();
}
function result(){
parent.classList.remove("working");
if(Math.random()>0.5){parent.classList.add("result");}
else{parent.classList.add("error");}
}
input();
#input{display:none;}
#working{display:none;}
#result{display:none;}
#error{display:none;}
#parent.input #input{display:block;}
#parent.working #working{display:block;}
#parent.result #result{display:block;}
#parent.error #error{display:block;}
<div id="parent">
<div id="input">INPUT. RUN</div>
<div id="working">WORKING. STOP</div>
<div id="result">RESULT. RESTART</div>
<div id="error">ERROR. RESTART</div>
</div>
This solution works but it feels unstable: in theory it would be possible for the parent element to have no classes (in which case nothing is displayed) or multiple ones (in which case you'd see multiple states at once). This shouldn't happen, but the only thing preventing it is the correctness of my script.
Question
Are there better ways to implement this idea of states, so that the HTML elements can't end up in inconsistent states?
Let’s consider the role which HTML plays in a state machine on the web. A machine has moving parts, it is dynamic, so the core of any machine on the web must be implemented in Javascript. HTML is useful only to provide the interface between the user and the machine. It’s a subtle distinction but it fundamentally changes the way you write it.
Have you ever used React? React provides the framework to create entire web applications as “state machines”. React’s mantra is “UI is a function of state”. In a React app, you have a single variable which contains the current state, rendering code which builds the UI based on the state, and core code (mostly event handlers) which updates the state.
Even if you don’t want to build in React, you can use the same general idea:
keep the current state in a Javascript variable (typically you’d use an object, but in this case we only need a string)
write a rendering function which reads the state and then builds the appropriate HTML to represent that state
in the event handlers for your links, do any operations which are required, update the state and call the rendering function
let state = null
let timer = null
// core code
const input = () => {
state = 'input'
render()
}
const run = () => {
state = 'working'
render()
timer = setTimeout(result,1500)
}
const stop = () => {
clearTimeout(timer)
state = 'input'
render()
}
const result = () => {
if(Math.random()>0.5)
state = 'result'
else
state = 'error'
render()
}
// rendering code
const render = () => {
let x = state
switch(state) {
case 'input':
x += ' run'
break
case 'working':
x += ' stop'
break
case 'result':
x += ' restart'
break
case 'error':
x += ' restart'
break
}
document.getElementById('container').innerHTML = x
}
// initialisation code
state = 'input'
render()
<div id="container"></div>

Pan map with mouse wheel click instead of left click

The default behavior of panning the map is via left click + drag I would like to change that behavior to be with wheel click + drag.
Is this possible?
That's handled by the ScreenSpaceCameraController, and is configurable. For example:
const viewer = new Cesium.Viewer("cesiumContainer");
// for 3D mode
viewer.scene.screenSpaceCameraController.rotateEventTypes = Cesium.CameraEventType.MIDDLE_DRAG;
// for 2D mode
viewer.scene.screenSpaceCameraController.translateEventTypes = Cesium.CameraEventType.MIDDLE_DRAG;
// remove MIDDLE_DRAG from the top of the tiltEventTypes.
viewer.scene.screenSpaceCameraController.tiltEventTypes.shift();
That last command above uses Array.shift to remove the first element of the tiltEventTypes array. The default value of this array (for many versions of Cesium) is shown here:
this.tiltEventTypes = [
CameraEventType.MIDDLE_DRAG,
CameraEventType.PINCH,
{
eventType: CameraEventType.LEFT_DRAG,
modifier: KeyboardEventModifier.CTRL,
},
{
eventType: CameraEventType.RIGHT_DRAG,
modifier: KeyboardEventModifier.CTRL,
},
];
This is showing us that one can still issue "tilt" events even after shifting away the MIDDLE_DRAG entry. We can CTRL-left-drag, for example, to get the same action.

Spark AR Native UI Picker

In Documentation page of Native UI Picker it says:
"The NativeUI Picker is an interface you can add to effects. It allows people using your effect to choose different options within it by selecting icons.
For example the user can tap different icons to change the texture shown in the effect"
I've made several effects with NativeUI texture "switcher", and was trying to implement NativeUI to switch not between textures, but effects (objects) themselves.
For example if I would make a FaceMesh with some texture on it, that would change with a screen tap and a particle system with another texture also with a change when the screen is tapped. How could I switch between those two using NativeUI?
I don't really like my current solution to this because it's not user friendly. I've used PatchEditor and FaceFinder, turning on/off visibility of the faceMesh and Emitter when eyebrows are raised. See the screenshot bellow:
I would really appreciate any suggestions,
Thank you!
// Load in modules
const NativeUI = require("NativeUI");
const Textures = require("Textures");
const Patches = require("Patches");
export const Diagnostics = require("Diagnostics");
// Create a number
let userNumber = 0;
const texture0 = Textures.get("number1");
const texture1 = Textures.get("number2");
const texture2 = Textures.get("number3");
const index = 0;
const configuration = {
selectedIndex: index,
items: [
{ image_texture: texture0 },
{ image_texture: texture1 },
{ image_texture: texture2 }
]
};
const picker = NativeUI.picker;
picker.configure(configuration);
picker.visible = true;
picker.selectedIndex.monitor().subscribe(function(index) {
userNumber = index.newValue;
// Send the number to the Patch Editor under the name 'userNumber'
Patches.setScalarValue("userNumber", userNumber);
// Debugging
Diagnostics.log("user selection = " + index.newValue);
});
Using NativeUI picker. The code above will output index value as userNumber(scalar) to patch editor.
Examples:
If user pick number 1 the output of userNumber will be 0,
If user pick number 2 the output of userNumber will be 1,
If user pick number 3 the output of userNumber will be 2,
etc.
You can use userNumber as switch combine with equal exactly
NativeUI Picker as Switch Picture

CesiumJS how to keep the zoom level of a Cesium.Viewer when the viewer.trackedEntity is changed

I have 2 different Cesium.Viewer instances, I want sync the 2 viewers when user zoom either one of them.
How to do that?
update:
In my app, I have 2 different Cesium.Viewer instances. But for this question here, I think it has nothing to do with the number of Cesium.Viewer. So I updated the question as below:
I have 2 planes flying on a Cesium.Viewer as shown in the attached screenshot, one is on the red course (ref as red plane) and the other is on the red course (ref as red plane).
Step-1: I tracked the yellow plane by double click it, then it looks like pic-1;
Step-2: I zoom out it to pic-2;
Step-3: I changed to track the red plane by double click it, and it looks like pic-3;
Step-4: I zoom out it to pic-4;
Whenever I changed the tracked entity (as step-3), I need to zoom out it manually again.
So, my question is how to keep the zoom level when changing the tracked entity?
Save current camera.view.scene
Detect moment when trackedEntity changed
Restore camera.view.scene
To save and restore you can use this code as an example:
var viewer = new Cesium.Viewer('cesiumContainer');
var savedView = {};
Cesium.CzmlDataSource.load('../../SampleData/simple.czml').then(function(dataSource) {
viewer.dataSources.add(dataSource);
Sandcastle.addToolbarButton('Save View', function() {
savedView.offset = viewer.scene.camera.position.clone();
});
Sandcastle.addToolbarButton('Restore View', function() {
viewer.trackedEntity._viewFrom._value = savedView.offset;
});
});
Note: viewFrom param should be in source czml for track. Smth like:
"viewFrom": {
"cartesian": [
-2080,
-1715,
779
]
},

Selectively remove Chrome browsing history

Is it possible to selectively remove items from Google Chrome browsing history? I have a website from my history that wants to be the default everytime I start a search with a specific letter, but I often reference my history to re-find things.
So I would like to remove all history from, say, www.pythonismyfavoritest.com without removing everything; is that possible?
Try searching www.pythonismyfavoritest.com in the search bar in chrome://history/ and then remove each item by clicking the check box in the left and then hitting the "remove selected items" button.
The chrome history api works with url such chrome://history/#q=hello&p=0
Here's something I wrote in JavaScript. It works through the Console Debugger. I tried using it in a bookmark but I get no response from the page.
** // UPDATE (07.28.15)
I added a shorter approach provided by #Denis Gorbachev to the checkbox targeting, which helped shorten some of this code. I also added "auto-stop" functionality, meaning the loop will stop once it has finally cleared the list.
** // UPDATE (08.20.14)I made a few changes to the code, to make it more user friendly. Other users may not be code-savvy, and others may simply prefer convenience. Therefore, I whipped up a couple buttons (start/stop) to control the usage; as well as address some "ASSERTION FAILED" exceptions/errors that were being thrown when attempted to run the script loop.. Enjoy!!
In your address bar, type in the following address to to the meat of the history page.. It's normally loaded in an iframe, with the left-side menu loaded in another frame.. // **
chrome://history-frame/
Next, load your Console Debugger/Viewer by pressing Ctrl+Shift+J(For Mac users, ⌘+⌥+J)
You can also press F12 and select the "Console" tab.
In the Console Debugger/Viewer, copy & paste the following code:
function removeItems() {
removeButton = document.getElementById('remove-selected');
overlayWindow = document.getElementById('overlay');
//revision (07.28.15): Replaced the For Loop targeting the checkboxes, thanks to Denis Gorbachev via comments (02.19.15)
Array.prototype.forEach.call(document.querySelectorAll("input[type=checkbox]"), function(node) {node.checked = "checked"})
setTimeout(function () {
if (removeButton.getAttribute("disabled") !== null) {
removeButton.removeAttribute("disabled")
}
/* revision (08.20.14): no longer binding to that condition, button should no longer be disabled, so click! */
if ((overlayWindow.hasAttribute("hidden")) && (overlayWindow.getAttribute("hidden") !== false)) {
removeButton.click();
}
/* revision (08.20.14): new Interval, to check against the overlay DIV containing the confirmation "Remove" button */
/* Attempting to click the button while the DIV's "hidden" attribute is in effect will cause FAILED ASSERTION */
stopButton = setInterval(function () {
if (overlayWindow.hasAttribute("hidden")) {
if (overlayWindow.getAttribute("hidden") == "false") {
hidden = false
} else {
hidden = true
}
} else {
hidden = false
}
if (!hidden) {
document.getElementById("alertOverlayOk").click();
clearInterval(stopButton)
}
}, 250)
}, 250)
}
//revision (08.20.14): Lets build our buttons to control this so we no longer need the console
//stop button (08.20.14)
var stopButton = document.createElement('button');
stopButton.setAttribute('id', "stopButton");
stopButton.innerHTML = "Stop";
stopButton.style.background = "#800";
stopButton.style.color = "#fff";
stopButton.style.display = "none";
stopButton.onclick = function () {
clearInterval(window.clearAllFiltered);
document.getElementById("stopButton").style.display = "none";
document.getElementById("startButton").style.display = ""
};
//start button (08.20.14)
var startButton = document.createElement('button');
startButton.setAttribute('id', "startButton");
startButton.innerHTML = "Start";
startButton.style.background = "#090";
startButton.style.color = "#fff";
startButton.onclick = function () {
window.clearAllFiltered = setInterval(function () {
/* revision (07.28.15): Stop the Loop automatically if there are no more items to remove */
if(document.getElementById("results-header").innerText=="No search results found."){
document.getElementById("stopButton").click();
}
if (document.getElementById("loading-spinner").getAttribute("hidden") !== null) {
removeItems()
}
}, 250); //adjust Time Here (1500 [millisec] = 1.5sec)
document.getElementById("stopButton").style.display = "";
document.getElementById("startButton").style.display = "none"
};
/* revision (08.20.14): Now we add our buttons, and we're ready to go! */
editingControls = document.getElementById('editing-controls');
editingControls.appendChild(stopButton);
editingControls.appendChild(startButton);
This removeItems function will select loop through all form inputs and check all checkboxes, enable the "Remove Selected Items" button and click it. After a half-second, it'll check if the "Are You Sure" prompt is displayed and, if so, click the "Yes/Remove" button automatically for you so that it will load a new list of items to do this process all over again..
The item is looped using the variable "clearAllFiltered", which is a setInterval loop, which is checking for the status of the "Loading" screen..
To start erasing your filtered history items, you can now click the green Start button.
** // UPDATE (07.28.2015) It will now stop on ITS OWN.
To stop the loop manually, you can now click the red Stop button. Simple as that!
1) Go to your history settings ( chrome://history/ )
2) In the top right hand corner will be a search bar with a 'Search History" button
3) Type in the sitename you want to remove from history, then click the button
4) Click the box on the first one, then scroll to the bottom of the page
5) Press and hold the Shift key, then click the last box (This will check all on that page)
6) Scroll back up and select the 'Remove Selected Items" Button
7) Repeat steps 4-6 until all your Youtube History is gone.
Hopefully Chrome will update this clear history feature, but for now this seems to be the fastest option
Easy way is Shift+Delete.
For example when you type "you", "youtube.com" will be shown as selected in suggestions. Just click Shift+Delete. Then retype "you" and you will see no "youtube.com" in that list anymore.
If you are talking about getting rid of the suggested search/auto-completion... then removing specific items from your chrome://history won't do it (in my experience). I want to fill in more detail to the answer #LacOniC gave.
In the screenshot you can see I typed "ba" and Chrome is suggesting completion based on my browsing history (the items in green).
In my experience, removing specific items from your history will not remove them from showing up in this address bar auto-completion.
To quickly remove these auto complete items:
Start typing a few letters that generate the offending suggestion.
Use your keyboard's arrow keys to select the suggestion you don't like (selected item is highlighted blue in screenshot).
Press shift+delete on windows or shift+fn+delete on mac to remove the selected item.