Una app web es la IU de una acción que usa Interactive Canvas. Puedes usar tecnologías web existentes (HTML, CSS y JavaScript) para diseñar y desarrollar tu aplicación web. En su mayor parte, Interactive Canvas puede procesar contenido web como un navegador, pero se aplican algunas restricciones para la privacidad y seguridad del usuario. Antes de comenzar a diseñar tu IU, ten en cuenta los principios de diseño descritos en la sección Design guidelines
.
El código HTML y JavaScript de la app web hace lo siguiente:
- Registra callbacks de eventos de Interactive Canvas.
- Inicializa la biblioteca JavaScript de Interactive Canvas.
- Proporciona una lógica personalizada para actualizar tu app web según el estado.
En esta página, se explican las formas recomendadas de compilar tu app web, cómo habilitar la comunicación entre la app web y la entrega, y los lineamientos y las restricciones generales.
Bibliotecas recomendadas
Si bien puedes usar cualquier método para compilar tu IU, Google recomienda que uses las siguientes bibliotecas:
- Greensock: Para crear animaciones complicadas.
- Pixi.js: Para dibujar gráficos 2D en WebGL.
- Three.js: Para dibujar gráficos 3D en WebGL.
- Dibujo HTML5 en lienzo: Para dibujos simples.
- Elemento DOM: Para contenido estático.
Arquitectura
Google recomienda usar una arquitectura de aplicación de una sola página. Este enfoque permite un rendimiento óptimo y admite una experiencia conversacional continua del usuario. Interactive Canvas se puede usar en conjunto con frameworks de frontend, como Vue, Angular y React, que ayudan con la administración del estado.
Archivo HTML
El archivo HTML define el aspecto de tu IU. Este archivo también carga la biblioteca JavaScript de Interactive Canvas, que permite la comunicación entre tu aplicación web y tu acción conversacional.
<!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>
Comunicación entre la entrega y la app web
Ahora que compilaste tu app web y la entrega y las cargaste en la biblioteca interactiva de Canvas en el archivo de tu app web, debes definir cómo interactúan la app web y la entrega. Para ello, modifica los archivos que contienen la lógica de tu aplicación web.
action.js
Este archivo contiene el código para definir callbacks y, luego, invocar métodos mediante interactiveCanvas
. Las devoluciones de llamada permiten que tu app web responda a información o solicitudes desde la acción conversacional, mientras que los métodos proporcionan una forma de enviar información o solicitudes a la acción conversacional.
Agrega interactiveCanvas.ready(callbacks);
a tu archivo HTML para inicializar y 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
Este archivo construye la escena de tu aplicación web. En este ejemplo, también controla los casos de éxito y error de la promesa que se mostró con sendTextQuery()
. El siguiente es un extracto 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;
});
Compatibilidad con interacciones táctiles
Tu acción de Interactive Canvas puede responder tanto al tacto del usuario como a las entradas de voz. Según los lineamientos de diseño de Interactive Canvas, debes desarrollar tu acción para que "priorice la voz". Dicho esto, algunas pantallas inteligentes admiten interacciones táctiles.
La compatibilidad táctil es similar a la compatibilidad con respuestas conversacionales; sin embargo, en lugar de una respuesta vocal del usuario, el código JavaScript del cliente busca interacciones táctiles y las usa para cambiar elementos en la aplicación web.
Puedes ver un ejemplo de esto en la muestra, que utiliza la 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;
});
...
En este caso, el valor de la variable spin
se envía a través de la API de interactiveCanvas
como una devolución de llamada update
. La entrega tiene una lógica que activa un intent basado en el valor de spin
.
...
app.intent('pause', (conv) => {
conv.ask(`Ok, I paused spinning. What else?`);
conv.ask(new HtmlResponse({
data: {
spin: false,
},
}));
});
...
Cómo agregar más funciones
Ahora que aprendiste los conceptos básicos, puedes mejorar y personalizar tu acción con las APIs específicas de Canvas. En esta sección, se explica cómo implementar estas APIs en tu acción de Interactive Canvas.
sendTextQuery()
El método sendTextQuery()
envía consultas de texto a la acción conversacional para invocar un intent de manera programática. En este ejemplo, se usa sendTextQuery()
para reiniciar el juego de giro de triángulos cuando el usuario hace clic en un botón. Cuando el usuario hace clic en el botón "Reiniciar el juego", sendTextQuery()
llama al intent Restart game
y muestra una promesa. Esta promesa da como resultado SUCCESS
si el intent está activado y BLOCKED
si no lo está. El siguiente fragmento activa el intent y controla los casos de éxito y error de la promesa:
//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}`);
}
});
...
Si la promesa da como resultado SUCCESS
, el intent Restart game
envía un HtmlResponse
a tu app web:
//index.js
...
app.intent('restart game', (conv) => {
conv.ask(new HtmlResponse({
data: {
command: 'RESTART_GAME',
},
...
Este HtmlResponse
activa la devolución de llamada onUpdate()
, que ejecuta el código en el siguiente fragmento de código RESTART_GAME
:
//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()
Se llama a la devolución de llamada OnTtsMark()
cuando incluyes una etiqueta <mark>
con un nombre único en la respuesta de SSML para el usuario. En los siguientes extractos del ejemplo de muñeco de nieve, OnTtsMark()
sincroniza la animación de la app web con el resultado de TTS correspondiente. Cuando la acción le dice al usuario Lo sentimos, perdiste, la app web deletrea la palabra correcta y muestra las letras al usuario.
El intent Game Over Reveal Word
incluye una marca personalizada en la respuesta que se envía al usuario cuando perdió el juego:
//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());
});
...
Luego, el siguiente fragmento de código registra la devolución de llamada OnTtsMark()
, verifica el nombre de la marca y ejecuta la función revealCorrectWord()
, que actualiza la app 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();
}
},
...
Restricciones
Ten en cuenta las siguientes restricciones cuando desarrolles tu app web:
- No hay cookies
- Sin almacenamiento local
- Sin ubicación geográfica
- Sin uso de la cámara
- No hay ventanas emergentes.
- Mantente por debajo del límite de memoria de 200 MB
- El encabezado de terceros ocupa la parte superior de la pantalla.
- No se pueden aplicar estilos a los videos
- Solo se puede usar un elemento multimedia a la vez
- Sin video HLS
- No hay base de datos Web SQL
- No es compatible con la interfaz
SpeechRecognition
de la API de Web Speech. - Sin grabación de audio o video
- No se aplica la configuración del modo oscuro
Uso compartido de recursos entre orígenes
Debido a que las apps web de Interactive Canvas están alojadas en un iframe y el origen está configurado como nulo, debes habilitar el uso compartido de recursos entre dominios (CORS) para tus servidores web y recursos de almacenamiento. Esto permite que tus recursos acepten solicitudes de orígenes nulos.
- Si tus imágenes y contenido multimedia se alojan en Firebase, consulta Crea vínculos dinámicos de dominios personalizados para configurar CORS.
- Si tus imágenes y medios están en Cloud Storage, consulta Configura el uso compartido de recursos entre dominios (CORS) para configurar CORS.