Um app da Web é a IU para uma ação que usa a tela interativa. É possível usar
tecnologias da Web existentes (HTML, CSS e JavaScript) para projetar e desenvolver
seu app da Web. Na maioria das vezes, a tela interativa é capaz de renderizar conteúdo da Web como
um navegador, mas há algumas restrições para a
privacidade e a segurança do usuário. Antes de começar a projetar a interface, considere os
princípios de design descritos na seção
Design guidelines
.
O HTML e o JavaScript do seu app da Web fazem o seguinte:
- Registra as callbacks do evento da tela interativa.
- Inicialize a biblioteca JavaScript de tela interativa.
- Forneça uma lógica personalizada para atualizar seu app da Web com base no estado.
Esta página aborda as maneiras recomendadas de criar seu app da Web, como ativar a comunicação entre o app da Web e o fulfillment e as diretrizes e restrições gerais.
Bibliotecas recomendadas
Embora você possa usar qualquer método para criar sua interface, o Google recomenda usar as seguintes bibliotecas:
- Greensock: para criar animações complicadas.
- Pixi.js: para desenhar gráficos 2D no WebGL.
- Three.js: para desenhar gráficos 3D no WebGL.
- Desenho em tela HTML5: para desenhos simples.
- Elemento DOM: para conteúdo estático.
Arquitetura
O Google recomenda o uso de uma arquitetura de aplicativo de página única. Essa abordagem permite um desempenho ideal e oferece suporte à experiência do usuário conversacional contínua. A tela interativa pode ser usada com frameworks de front-end, como Vue, Angular e React, que ajudam no gerenciamento do estado.
Arquivo HTML
O arquivo HTML define a aparência da interface. Esse arquivo também carrega a biblioteca JavaScript de tela interativa, que permite a comunicação entre seu app da Web e a ação de conversa.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Immersive Canvas Sample</title>
<!-- Disable favicon requests -->
<link rel="shortcut icon" type="image/x-icon" href="data:image/x-icon;,">
<!-- Load Interactive Canvas JavaScript -->
<script src="https://www.gstatic.com/assistant/df-asdk/interactivecanvas/api/interactive_canvas.min.js"></script>
<!-- Load PixiJS for graphics rendering -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/pixi.js/4.8.7/pixi.min.js"></script>
<!-- Load Stats.js for fps monitoring -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/stats.js/r16/Stats.min.js"></script>
<!-- Load custom CSS -->
<link rel="stylesheet" href="css/main.css">
</head>
<body>
<div id="view" class="view">
<div class="debug">
<div class="stats"></div>
<div class="logs"></div>
</div>
</div>
<!-- Load custom JavaScript after elements are on page -->
<script src="js/main.js"></script>
<script src="js/log.js"></script>
</body>
</html>
Comunicação entre o fulfillment e o app da Web
Agora que você criou o app da Web e o fulfillment e carregou na biblioteca de tela interativa no arquivo do app da Web, é necessário definir como o app da Web e o fulfillment interagem. Para fazer isso, modifique os arquivos que contêm a lógica do app da Web.
action.js
Esse arquivo contém o código para definir
callbacks
e invocar métodos
usando interactiveCanvas
. Os callbacks permitem que seu app da Web responda a
informações ou solicitações da ação de conversa. Os métodos
oferecem uma maneira de enviar informações ou solicitações para a ação de conversa.
Adicione interactiveCanvas.ready(callbacks);
ao arquivo HTML para inicializar e registrar callbacks:
//action.js
class Action {
constructor(scene) {
this.canvas = window.interactiveCanvas;
this.scene = scene;
const that = this;
this.commands = {
TINT: function(data) {
that.scene.sprite.tint = data.tint;
},
SPIN: function(data) {
that.scene.sprite.spin = data.spin;
},
RESTART_GAME: function(data) {
that.scene.button.texture = that.scene.button.textureButton;
that.scene.sprite.spin = true;
that.scene.sprite.tint = 0x0000FF; // blue
that.scene.sprite.rotation = 0;
},
};
}
/**
* Register all callbacks used by Interactive Canvas
* executed during scene creation time.
*
*/
setCallbacks() {
const that = this;
// declare interactive canvas callbacks
const callbacks = {
onUpdate(data) {
try {
that.commands[data.command.toUpperCase()](data);
} catch (e) {
// do nothing, when no command is sent or found
}
},
};
// called by the Interactive Canvas web app once web app has loaded to
// register callbacks
this.canvas.ready(callbacks);
}
}
main.js
Esse arquivo constrói a cena para seu app da Web. Neste exemplo, ele também processa
os casos de sucesso e falha da promessa retornada com sendTextQuery()
. Confira
um trecho de main.js
:
// main.js
const view = document.getElementById('view');
// initialize rendering and set correct sizing
this.renderer = PIXI.autoDetectRenderer({
transparent: true,
antialias: true,
resolution: this.radio,
width: view.clientWidth,
height: view.clientHeight,
});
view.appendChild(this.element);
// center stage and normalize scaling for all resolutions
this.stage = new PIXI.Container();
this.stage.position.set(view.clientWidth / 2, view.clientHeight / 2);
this.stage.scale.set(Math.max(this.renderer.width,
this.renderer.height) / 1024);
// load a sprite from a svg file
this.sprite = PIXI.Sprite.from('triangle.svg');
this.sprite.anchor.set(0.5);
this.sprite.tint = 0x00FF00; // green
this.sprite.spin = true;
this.stage.addChild(this.sprite);
// toggle spin on touch events of the triangle
this.sprite.interactive = true;
this.sprite.buttonMode = true;
this.sprite.on('pointerdown', () => {
this.sprite.spin = !this.sprite.spin;
});
Suporte a interações por toque
Sua ação de tela interativa pode responder ao toque do usuário e às entradas vocais. De acordo com as diretrizes de design da tela interativa, você precisa desenvolver a ação para priorizar a voz. Alguns smart displays são compatíveis com interações por toque.
O suporte a toque é semelhante ao suporte a respostas conversacionais. No entanto, em vez de uma resposta vocal do usuário, o JavaScript do lado do cliente procura interações de toque e as usa para mudar elementos no app da Web.
Veja um exemplo disso na amostra, que usa a biblioteca Pixi.js:
...
this.sprite = PIXI.Sprite.from('triangle.svg');
...
this.sprite.interactive = true; // Enables interaction events
this.sprite.buttonMode = true; // Changes `cursor` property to `pointer` for PointerEvent
this.sprite.on('pointerdown', () => {
this.sprite.spin = !this.sprite.spin;
});
...
Nesse caso, o valor da variável spin
é enviado pela
API interactiveCanvas
como um callback update
. O fulfillment tem uma lógica
que aciona uma intent com base no valor de spin
.
...
app.intent('pause', (conv) => {
conv.ask(`Ok, I paused spinning. What else?`);
conv.ask(new HtmlResponse({
data: {
spin: false,
},
}));
});
...
Adicionar mais recursos
Agora que você aprendeu o básico, pode melhorar e personalizar sua ação com APIs específicas para a tela. Esta seção explica como implementar essas APIs na ação de tela interativa.
sendTextQuery()
O método sendTextQuery()
envia consultas de texto para a ação de conversa
para invocar uma intent de forma programática. Esse exemplo usa sendTextQuery()
para
reiniciar o jogo de rotação triangular quando o usuário clica em um botão. Quando o usuário
clica no botão "Reiniciar jogo", sendTextQuery()
chama a intent Restart game
e retorna uma promessa. Essa promessa vai resultar em SUCCESS
se a intent for
acionada e BLOCKED
se não for. O snippet a seguir aciona a intent e processa os casos de sucesso e falha da promessa:
//main.js
...
that.action.canvas.sendTextQuery('Restart game')
.then((res) => {
if (res.toUpperCase() === 'SUCCESS') {
console.log(`Request in flight: ${res}`);
that.button.texture = that.button.textureButtonDisabled;
that.sprite.spin = false;
} else {
console.log(`Request in flight: ${res}`);
}
});
...
Se a promessa resultar em SUCCESS
, a intent Restart game
enviará um HtmlResponse
ao seu app da Web:
//index.js
...
app.intent('restart game', (conv) => {
conv.ask(new HtmlResponse({
data: {
command: 'RESTART_GAME',
},
...
Esse HtmlResponse
aciona o callback onUpdate()
, que executa o código
no snippet RESTART_GAME
abaixo:
//action.js
...
RESTART_GAME: function(data) {
that.scene.button.texture = that.scene.button.textureButton;
that.scene.sprite.spin = true;
that.scene.sprite.tint = 0x0000FF; // blue
that.scene.sprite.rotation = 0;
},
...
OnTtsMark()
O callback OnTtsMark()
é chamado quando você inclui uma tag <mark>
com um nome exclusivo na resposta SSML para o usuário. Nos trechos a seguir do exemplo do Snowman,
OnTtsMark()
sincroniza a animação do app da Web com a saída de TTS
correspondente. Quando a Ação disser ao usuário Desculpe, você perdeu, o app da Web soletra
a palavra correta e mostra as letras para o usuário.
A intent Game Over Reveal Word
inclui uma marca personalizada na resposta ao
usuário que ele perdeu o jogo:
//index.js
...
app.intent('Game Over Reveal Word', (conv, {word}) => {
conv.ask(`<speak>Sorry, you lost.<mark name="REVEAL_WORD"/> The word is ${word}.` +
`${PLAY_AGAIN_INSTRUCTIONS}</speak>`);
conv.ask(new HtmlResponse());
});
...
O snippet de código a seguir registra o callback OnTtsMark()
, verifica o nome
da marca e executa a função revealCorrectWord()
, que atualiza o app da Web:
//action.js
...
setCallbacks() {
const that = this;
// declare assistant canvas action callbacks
const callbacks = {
onTtsMark(markName) {
if (markName === 'REVEAL_WORD') {
// display the correct word to the user
that.revealCorrectWord();
}
},
...
Restrições
Considere as seguintes restrições ao desenvolver seu app da Web:
- Sem cookies
- Sem armazenamento local
- Sem geolocalização
- Sem uso da câmera
- Sem pop-ups
- Ficar abaixo do limite de 200 MB de memória
- O cabeçalho de terceiros ocupa a parte superior da tela
- Não é possível aplicar estilos aos vídeos
- Somente um elemento de mídia pode ser usado por vez
- Nenhum vídeo HLS
- Nenhum banco de dados Web SQL
- Sem suporte para a interface
SpeechRecognition
da API Web Speech. - Sem gravação de áudio ou vídeo
- A configuração de modo escuro não se aplica
Compartilhamento de recursos entre origens
Como os apps da Web de tela interativa são hospedados em um iframe e a origem está definida como nula, ative o compartilhamento de recursos entre origens (CORS, na sigla em inglês) para os servidores da Web e recursos de armazenamento. Isso permite que seus recursos aceitem solicitações de origens nulas.
- Se a mídia e as imagens estiverem hospedadas com o Firebase, consulte Criar links dinâmicos de domínio personalizado para configurar o CORS.
- Se as mídias e imagens estiverem no Cloud Storage, consulte Como configurar o compartilhamento de recursos entre origens (CORS) para configurar o CORS.