Utilizando la API del Gamepad para una mejor experiencia de juego en la web

Rate this content
Bookmark

Esta charla explora el uso e impacto de la API del Gamepad en el espacio de los juegos web. La API del Gamepad te permite conectar y utilizar varios controladores de juegos con los navegadores, pero dado que esta API está en etapas muy tempranas, rastrear diferentes entradas de controladores en diferentes navegadores se vuelve extremadamente desafiante. Con este propósito, he lanzado una biblioteca de código abierto que proporciona soporte para eventos de presión de botones, movimiento de ejes y efectos de vibración en los navegadores. Nos enfocaremos en cómo podemos aprovechar esta biblioteca para brindar mejores experiencias de juego a los consumidores en la web.

21 min
28 Sep, 2023

Video Summary and Transcription

La charla discute la API del Gamepad para su uso en el desarrollo de juegos en la plataforma web. Explora la API del Gamepad, que permite a los desarrolladores conectar dispositivos de juegos al navegador y utilizarlos en aplicaciones de juegos. La implementación de la API del Gamepad implica rastrear las pulsaciones de botones y los movimientos del joystick utilizando el request animation frame. La charla también presenta la biblioteca JoypadJS, que extiende la API del Gamepad para rastrear las pulsaciones de botones, los movimientos de los ejes y proporcionar retroalimentación háptica. JoypadJS funciona en navegadores modernos con soporte para la API del Gamepad y se utiliza en juegos, aplicaciones interactivas y proyectos de IoT.

Available in English

1. Introducción a la API de Gamepad web

Short description:

Hola, y bienvenidos a mi charla para la Cumbre de Desarrollo de Juegos JS de este año. Hoy hablaré sobre la API de Gamepad web y cómo podemos extenderla y utilizarla de manera efectiva para crear juegos en la web. Hablemos sobre la plataforma web por un momento antes de adentrarnos en la API de Gamepad web. La web ha crecido mucho en la última década aproximadamente, y continúa creciendo a un ritmo rápido. El navegador se ha convertido en algo más que un renderizador o visor de documentos, y es gracias a este crecimiento y la continua adición de APIs ricas en funciones que los desarrolladores pueden crear aplicaciones web mucho más interactivas y eficientes.

Mi nombre es Arun. Y hoy hablaré sobre la API de Gamepad web y cómo podemos extenderla y utilizarla de manera efectiva para crear juegos en la web.

Primero, un poco sobre mí. Soy un ingeniero senior en Bloomberg, y principalmente trabajo con tecnologías web, construyendo software web empresarial y herramientas basadas en el navegador. También soy un entusiasta del código abierto. He contribuido a varios proyectos de código abierto, y algunos de mis propios proyectos, principalmente bibliotecas de extensión y módulos para Node, React, Angular, etc. Puedes visitar mi sitio web si quieres saber más sobre mí y mi trabajo.

Bien, sin más preámbulos, vamos directo al grano. Hablemos sobre la plataforma web por un momento antes de adentrarnos en la API de Gamepad web. Supongo que primero debemos reconocer el hecho de que la web ha crecido mucho en la última década aproximadamente, y continúa creciendo a un ritmo rápido. Todos sabemos que el navegador se ha convertido en algo más que un renderizador o visor de documentos, y es gracias a este crecimiento y la continua adición de APIs ricas en funciones que los desarrolladores pueden crear aplicaciones web mucho más interactivas y eficientes. Mejoras como eventos de luz ambiental, gráficos acelerados por GPU, acceso al sistema de archivos, y APIs de nivel inferior que proporcionan control nativo y acceso a hardware no solo permiten a los desarrolladores atender a una variedad más amplia de usuarios sino que también les permite admitir varios tipos de casos de uso. Lo cual no hubiera sido posible sin estas mejoras en la plataforma web. Aunque algunas de estas APIs están en etapas muy tempranas en este momento, parecen ser realmente, realmente prometedoras y dan una idea de cómo podría ser el desarrollo web en los próximos años.

2. Introducción a la API de GamePad

Short description:

Los navegadores se han vuelto lo suficientemente potentes como para manejar cálculos gráficos complejos para jugar videojuegos. La forma principal de entrada para los juegos web ha sido el teclado o el mouse, lo cual puede ser limitante para los dispositivos de pantalla táctil. La especificación GamePad permite a los desarrolladores conectar dispositivos de juego al navegador y utilizarlos en aplicaciones de juegos. La API expone un método en la interfaz Navigator para obtener información sobre los GamePads conectados y sus botones. La API de GamePad recomienda un diseño estándar de facto llamado Diseño Estándar de GamePad.

Los navegadores se han vuelto extremadamente potentes y capaces como para manejar cálculos gráficos complejos, especialmente para jugar videojuegos. Desde juegos de desplazamiento en 2D, emulación retro, hasta juegos en 3D de alta gama. Es posible jugar casi cualquier tipo de juego en la web hoy en día.

Y para la mayoría de estos juegos que vemos y jugamos en la web, la forma principal de entrada siempre ha sido mediante el teclado o el mouse. Y para dispositivos de pantalla táctil, hemos visto diseños de controles en pantalla como estos, que a veces pueden dificultar la experiencia de juego. Y el uso de este tipo de controles puede resultar bastante complicado para los jugadores que prefieren controles más naturales, como un pad direccional o un joystick para los movimientos del personaje.

Ahora, los juegos de escritorio proporcionan esta flexibilidad de utilizar dispositivos externos como gamepads y joysticks, tal vez porque tienen soporte nativo incorporado. Pero cuando se trata de la web, durante mucho tiempo no ha habido soporte nativo para esto en absoluto. Los desarrolladores tenían que diseñar interfaces complejas basadas en el mouse o el teclado para los controles del juego, lo cual puede ser bastante complicado de operar.

Así que, hace unos años, el W3C introdujo la especificación GamePad, que define una interfaz de bajo nivel para representar dispositivos de juego. Esto significa que utilizando esta API, los desarrolladores podrán conectar GamePads y dispositivos similares al navegador y luego utilizarlos en sus aplicaciones de juegos. Esto significa que podrás utilizar dispositivos como el DualShock, Joy-Con e incluso dispositivos de próxima generación como el DualSense y los controladores de Xbox Series X.

Hasta el día de hoy, la especificación GamePad sigue siendo un trabajo en progreso. Se publica como un borrador de trabajo. La especificación tiene la intención de convertirse en una recomendación del W3C. Por ahora, podemos ver que la API en sí es compatible con todos los navegadores modernos, lo cual es definitivamente una buena señal. Así que echemos un vistazo a los detalles de la API en sí. La API expone un método en la interfaz Navigator que devuelve una lista de objetos GamePad, y cada objeto GamePad representa un GamePad que está conectado al navegador. Ahora, esta interfaz GamePad devuelve información útil sobre el GamePad conectado. Información relacionada con los botones, los ejes, que son básicamente los joysticks. Los estados actuales y otra información como el ID del dispositivo, el estado, etc. Si observamos de cerca los botones del GamePad, vemos que cada botón es una instancia de la interfaz GamePadButton. Esto representa un botón individual en el GamePad y permite acceder al estado actual del botón. Utilizando esto, podemos determinar si el botón fue presionado o no y llevar a cabo la acción correspondiente en el juego. Ahora, cada fabricante de GamePads crea muchos tipos diferentes de productos y cada uno puede tener un estilo o diseño único de botones y ejes. Pero es responsabilidad del agente de usuario, por supuesto, admitir tantos de estos como sea posible, por eso la API de GamePad recomienda un diseño estándar de facto llamado Diseño Estándar de GamePad. Y este diseño se ha vuelto popular gracias a muchas consolas de juegos. Y en este diseño, los botones y ejes se disponen en un orden particular que veremos. Así es como se ve el Diseño Estándar de GamePad y en este diseño, las ubicaciones de los botones se colocan en un grupo izquierdo de cuatro botones, un grupo derecho de cuatro botones, un grupo central de tres botones.

3. Seguimiento de Pulsaciones de Botones del GamePad

Short description:

Algunos controladores pueden tener cuatro botones y un par de joysticks. La API de GamePad proporciona eventos para la conexión y desconexión del GamePad. Sin embargo, no hay una forma estandarizada de detectar las pulsaciones de botones o los movimientos del joystick. Para rastrear estos estados, podemos realizar una consulta continua de cambios o utilizar request animation frame para actualizaciones más consistentes.

Algunos controladores pueden tener cuatro. Un par de botones frontales, o botones de hombro, como se les llama, en el lado izquierdo y derecho del GamePad. Y un par de joysticks.

Ten en cuenta que, dado que la API de GamePad está en sus primeras etapas, el diseño estándar de los botones del GamePad puede variar de un navegador a otro. La imagen aquí muestra los mapeos de botones predeterminados para Google Chrome.

Entonces, ¿cómo podemos rastrear estos cambios en el estado de los botones? ¿Existen eventos expuestos por la API de GamePad que podamos utilizar? Veamos.

La API de GamePad proporciona el evento GamePad Connected, que se emite cada vez que se conecta un nuevo GamePad al navegador. Si el GamePad ya está conectado, cuando la página se carga y obtiene el enfoque, entonces el evento se emite cada vez que hay alguna actividad en el GamePad, ya sabes, una pulsación de botón o un movimiento en un joystick. De manera similar, hay un evento GamePad Disconnected, que se emite cuando se desconecta un GamePad del navegador.

Sin embargo, no hay una forma estandarizada de detectar las pulsaciones de botones del GamePad o los movimientos del joystick. Ya se ha visto que la interfaz GamePad devuelve información útil sobre los estados de acceso a los botones, pero no hay un evento real que se emita cuando el usuario realiza estas acciones. Actualmente, la API de GamePad solo admite los eventos GamePad Connected y Disconnected.

Entonces, intentemos explorar qué podemos hacer para rastrear los botones del GamePad, las pulsaciones y los movimientos de acceso. Podríamos tener un GamePad conectado al navegador y, para rastrear los estados de los botones y el acceso, podemos realizar una consulta continua de los cambios en algo como una llamada de intervalo establecido, y esto es lo más simple que podemos hacer. Si observas el código aquí, estamos registrando la información del primer botón del primer GamePad conectado al navegador. Por eso usamos el 0 a X. Esto funciona bien. Podemos capturar el estado del botón a medida que se actualiza, pero esto puede no ser la mejor forma de capturar esta información. Veamos por qué.

Todos sabemos que en JavaScript, todo se ejecuta en un solo hilo y las funciones de temporizador no son una excepción. Para ejecutar código utilizando setInterval, especificamos una devolución de llamada que se ejecuta cada X milisegundos. A veces, los retrasos proporcionados a estas funciones de temporizador no se respetan debido a la ejecución prioritaria de tareas intensivas en recursos, si las hay en la cola de tareas. Y esto conduce a intervalos de retraso inconsistentes. Es posible que hayas notado una interrupción al usar setInterval para animar elementos de la página. Y esto se debe a una actualización innecesaria y forzada de los elementos de la página. Incluso antes de que la pantalla del usuario esté lista para procesar y representar esas actualizaciones. Y esto se llama bloqueo del diseño y se debe evitar a toda costa.

Entonces, ¿qué más podemos hacer aquí? Podemos usar request animation frame. Ahora, la devolución de llamada proporcionada a request animation frame se garantiza que se ejecutará al inicio del fotograma. Lo que significa que la devolución de llamada especificada se llamará antes de que ocurra la próxima operación de repintado.

4. Implementación de la API de Gamepad

Short description:

La función de devolución de llamada se solicita alrededor de 60 veces por segundo o 60 FPS, coincidiendo con la frecuencia de actualización de la pantalla. Se recomienda utilizar request animation frame para operaciones o animaciones que necesiten mantenerse sincronizadas con el renderizado. La API de Gamepad permite consultar objetos de Gamepad y acceder a los estados de los botones de manera efectiva utilizando request animation frame. Podemos detectar gamepads conectados o desconectados, acceder a cambios en el estado de los botones o ejes, y proporcionar esta funcionalidad como una API para reutilizar en aplicaciones de juegos. La implementación del bucle del juego obtiene los gamepads conectados, verifica cambios en el estado de los botones y ejes, y utiliza manejadores de eventos separados para cada uno. El valor de retorno de request animation frame es un ID de solicitud único que se puede utilizar para solicitar o cancelar solicitudes de devolución de llamada de fotogramas. El ButtonEventListener realiza un seguimiento de los eventos de los botones mediante la verificación de los estados de los botones y el envío de eventos personalizados en el objeto window.

El número de veces que se solicita la función de devolución de llamada es alrededor de 60 veces por segundo o 60 FPS. Pero generalmente coincide con la frecuencia de actualización de la pantalla. Por eso, para la mayoría de las operaciones o animaciones que deben mantenerse sincronizadas con el renderizado, se recomienda utilizar request animation frame para obtener el mejor rendimiento.

Volviendo a la API de Gamepad, podemos ver que consultar los objetos de Gamepad y acceder a los estados de los botones se puede hacer de manera efectiva utilizando request animation frame. En el contexto de un videojuego, un bucle de juego es algo que verifica continuamente la entrada del usuario, actualiza el estado del juego y luego renderiza la escena. Request animation frame es adecuado para esto porque podemos realizar todas estas operaciones en su devolución de llamada y se mantendrá sincronizado con las tareas de repintado en cada fotograma.

Creo que así es como se debe obtener la entrada del usuario en una aplicación de juegos. Entonces, para resumir, podemos detectar si un gamepad está conectado o desconectado del navegador. Eso es algo que el gamepad ya admite. Podemos acceder a los cambios en el estado de los botones o ejes utilizando request animation frame. Ahora, idealmente, lo que queremos hacer es proporcionar esta funcionalidad en forma de una API para que se pueda reutilizar en cualquier aplicación de juegos. Veamos cómo podemos extender la API de gamepad para lograr esto. Comencemos con la implementación del bucle de juego. Aquí tenemos un método de inicio. En este método, básicamente estamos obteniendo todos los gamepads que están conectados al navegador. Y luego los recorremos para verificar los cambios en el estado de los botones y ejes. Y para cada gamepad que está conectado al navegador, queremos escuchar cualquier cambio de estado que ocurra en cualquiera de los botones o ejes. Por eso tenemos manejadores de eventos separados para ambos. El método de inicio llama a request animation frame para que se ejecute de forma recursiva y podamos realizar un seguimiento de los cambios en el estado de los botones y ejes en cada fotograma.

Una cosa a tener en cuenta aquí es el valor de retorno del método request animation frame. Devuelve un valor no entero, que es el ID de solicitud que identifica de manera única la función de devolución de llamada. Y podemos usar este ID para solicitar o cancelar las solicitudes de devolución de llamada de fotogramas. Es posible que debamos asegurarnos de detener el bucle, cancelar todas las solicitudes de devolución de llamada y liberar la memoria cuando ya no sea necesario. Por ejemplo, cuando todos los gamepads se hayan desconectado y no sea necesario obtener los cambios en el estado de los botones o ejes.

Ahora veamos la implementación de ButtonEventListener. Para realizar un seguimiento de los eventos de los botones, recorremos todos los botones del gamepad, verificamos el estado del botón, si ha sido presionado o no. Y dependiendo de eso, utilizamos DispatchEvent para enviar cualquier evento en el objeto window. Y utilizamos la API de eventos personalizados para definir el evento en sí, que se llama GamePadButtonPressed, y pasamos los datos del evento a este evento personalizado, que contiene la información sobre el botón presionado. Y utilizando esto, podemos escuchar el evento GamePadButtonPressed en el objeto window y realizar un seguimiento de los cambios de estado en cualquiera de los botones del gamepad.

5. Seguimiento de Movimientos del Joystick

Short description:

Un consejo es mantener un mapeo interno de clave-valor de todos los botones y sus estados, y descartar estos valores cuando el estado cambie. Ahora, para el seguimiento de los movimientos del joystick, primero determinamos el número total de sticks en el GamePad. Recorremos todos los ejes y determinamos qué stick se movió. También calculamos la dirección del movimiento basándonos en los índices y los valores de los ejes. Utilizamos el método dispatch event para enviar un evento al objeto window con los datos del evento requeridos.

Un consejo es mantener un mapeo interno de clave-valor de todos los botones y sus estados, y descartar estos valores cuando el estado cambie. De esta manera, podremos enviar los eventos personalizados solo cuando el estado cambie a positivo.

Ahora, para el seguimiento de los movimientos del joystick, primero determinamos el número total de sticks en el GamePad. En el diseño estándar del GamePad, tenemos dos joysticks. Y cada stick tiene dos ejes que representan la dirección del movimiento. Y cada eje está representado por un índice.

Recorremos todos los ejes y determinamos qué stick se movió. Los ejes 0 y 1 representan el stick izquierdo. Y los ejes 2 y 3 representan el stick derecho. Entonces, si el índice actual es menor que el número total de sticks, es el stick izquierdo; de lo contrario, es el stick derecho. También calculamos la dirección del movimiento basándonos en los índices y los valores de los ejes. Un valor negativo representa un movimiento hacia la izquierda o arriba, y un valor positivo representa un movimiento hacia la derecha o abajo. Nuevamente, utilizamos el método dispatch event para enviar un evento al objeto window con los datos del evento requeridos. El evento en sí es, una vez más, un evento personalizado llamado GamePadAxisMoved, en el cual podemos realizar un seguimiento de los cambios de estado en cualquiera de los ejes del GamePad.

6. Extensión de la API GamePad con la biblioteca JoypadJS

Short description:

Ahora, al escuchar el botón presionado del GamePad, se agregó un objeto window que puede devolver la información del botón presionado. Y el evento GamePadAxisMoved devolvería la información del eje que se movió. Hemos podido extender la API GamePad para realizar un seguimiento de los botones presionados y los movimientos del eje. Existe una biblioteca de código abierto llamada JoypadJS que te permite conectar y usar varios controladores de juegos en navegadores que admiten la API GamePad. Es muy pequeña, no tiene dependencias y admite botones presionados, movimientos del eje, eventos y más. Expone una API basada en eventos para manejar la conexión del gamepad, desconexión, botones presionados y movimientos del eje. La biblioteca también proporciona un método de vibración para retroalimentación háptica y un método de configuración para ajustes globales. JoypadJS funciona en todos los navegadores modernos con soporte para la API GamePad y se utiliza en juegos, aplicaciones interactivas y proyectos de IoT. La API GamePad está en etapas iniciales, por lo que los detalles y las especificaciones de la API pueden cambiar en el futuro. Echa un vistazo a JoypadJS en bit.ly/joypad_JS.

Ahora, al escuchar el botón presionado del GamePad, se agregó un objeto window que puede devolver la información del botón presionado. Y el evento GamePadAxisMoved devolvería la información del eje que se movió. Eso es prácticamente todo. Hemos podido extender la API GamePad, en particular la interfaz GamePad, para realizar un seguimiento de los botones presionados y los movimientos del eje.

Ahora, lo bueno es que no tienes que hacer toda esta implementación por ti mismo, ¿verdad? Existe una biblioteca de código abierto que puedes usar fácilmente en tus juegos que creé, por cierto. Y esta biblioteca se llama JoypadJS. Es una biblioteca que te permite conectar y usar varios controladores de juegos en navegadores que admiten la API GamePad. Es muy pequeña, no tiene dependencias y admite botones presionados, movimientos del eje, eventos y mucho más. Puedes echar un vistazo en bit.ly/joypad_JS. Es una biblioteca que publiqué hace algún tiempo bajo la licencia MIT. Expone una API basada en eventos que se puede utilizar para suscribirse a ciertos eventos que son detectados y despachados internamente por la biblioteca.

Entonces, este es solo un ejemplo. Puedes suscribirte a eventos simplemente especificando un nombre de evento y una devolución de llamada. Y esta devolución de llamada se activa cada vez que se desencadena el evento especificado. Admite eventos para manejar la conexión del gamepad, desconexión, botones presionados y movimientos del eje. También expone un método de vibración que se puede utilizar para proporcionar retroalimentación háptica al usuario. Básicamente, puedes configurar la duración y la intensidad y personalizar la vibración del gamepad. Es algo que es compatible con todos los navegadores modernos, excepto Firefox, que yo sepa. La biblioteca también proporciona un método de configuración que se puede utilizar para configurar ajustes globales para la vibración, umbral de movimiento del eje, que es como la rigidez del movimiento, y la opción de asignación de botones personalizada, que se puede utilizar para establecer asignaciones de botones personalizadas para mejorar el seguimiento del estado de los botones en diferentes navegadores. Como mencioné anteriormente, diferentes navegadores pueden implementar su propia asignación de botones estándar para gamepads, ¿verdad? Entonces, utilizando esta opción, puedes asegurarte de que las asignaciones de botones sean precisas y que todos los botones funcionen como se espera en todos los navegadores. El soporte del navegador para la biblioteca es bastante bueno, JoypadJS funciona en todos los navegadores modernos que admiten la API GamePad, por supuesto. Los desarrolladores han estado utilizando la biblioteca en todo tipo de proyectos, juegos, aplicaciones interactivas, IoT, lo cual es fantástico. También aprendí que RPG.js utiliza esta biblioteca para el soporte de gamepad, RPG.js es como un marco de creación de RPG basado en web. Así que sí, siéntete libre de probarlo y compartir cualquier comentario que puedas tener. Me gustaría señalar nuevamente que la API GamePad está en etapas iniciales. Por lo tanto, los detalles y las especificaciones de la API pueden cambiar en el futuro. Nuevamente, puedes echar un vistazo en bit.ly/joypad_JS. Como probablemente ya habrás adivinado, he estado investigando mucho sobre el tema y he publicado algunos blogs que podrían ser realmente útiles. Puedes consultarlos aquí. Y eso es todo. Si tienes alguna pregunta, sugerencia o simplemente quieres saludar, no dudes en contactarme en amdisuser92 en Twitter. Muchas gracias por unirte y escucharme y disfruta del resto de la conferencia. ♪♪♪

Check out more articles and videos

We constantly think of articles and videos that might spark Git people interest / skill us up or help building a stellar career

JS GameDev Summit 2022JS GameDev Summit 2022
33 min
Building Fun Experiments with WebXR & Babylon.js
Top Content
During this session, we’ll see a couple of demos of what you can do using WebXR, with Babylon.js. From VR audio experiments, to casual gaming in VR on an arcade machine up to more serious usage to create new ways of collaboration using either AR or VR, you should have a pretty good understanding of what you can do today.
Check the article as well to see the full content including code samples: article. 
React Summit 2023React Summit 2023
32 min
How Not to Build a Video Game
In this talk we'll delve into the art of creating something meaningful and fulfilling. Through the lens of my own journey of rediscovering my passion for coding and building a video game from the ground up with JavaScript and React, we will explore the trade-offs between easy solutions and fast performance. You will gain valuable insights into rapid prototyping, test infrastructure, and a range of CSS tricks that can be applied to both game development and your day-to-day work.

Workshops on related topic

JSNation 2023JSNation 2023
116 min
Make a Game With PlayCanvas in 2 Hours
Featured WorkshopFree
In this workshop, we’ll build a game using the PlayCanvas WebGL engine from start to finish. From development to publishing, we’ll cover the most crucial features such as scripting, UI creation and much more.
Table of the content:- Introduction- Intro to PlayCanvas- What we will be building- Adding a character model and animation- Making the character move with scripts- 'Fake' running- Adding obstacles- Detecting collisions- Adding a score counter- Game over and restarting- Wrap up!- Questions
Workshop levelFamiliarity with game engines and game development aspects is recommended, but not required.
JS GameDev Summit 2022JS GameDev Summit 2022
121 min
PlayCanvas End-to-End : the quick version
Top Content
WorkshopFree
In this workshop, we’ll build a complete game using the PlayCanvas engine while learning the best practices for project management. From development to publishing, we’ll cover the most crucial features such as asset management, scripting, audio, debugging, and much more.
JS GameDev Summit 2022JS GameDev Summit 2022
86 min
Introduction to WebXR with Babylon.js
Workshop
In this workshop, we'll introduce you to the core concepts of building Mixed Reality experiences with WebXR and Balon.js.
You'll learn the following:- How to add 3D mesh objects and buttons to a scene- How to use procedural textures- How to add actions to objects- How to take advantage of the default Cross Reality (XR) experience- How to add physics to a scene
For the first project in this workshop, you'll create an interactive Mixed Reality experience that'll display basketball player stats to fans and coaches. For the second project in this workshop, you'll create a voice activated WebXR app using Balon.js and Azure Speech-to-Text. You'll then deploy the web app using Static Website Hosting provided Azure Blob Storage.
React Advanced Conference 2021React Advanced Conference 2021
168 min
How to create editor experiences your team will love
Workshop
Content is a crucial part of what you build on the web. Modern web technologies brings a lot to the developer experience in terms of building content-driven sites, but how can we improve things for editors and content creators? In this workshop you’ll learn how use Sanity.io to approach structured content modeling, and how to build, iterate, and configure your own CMS to unify data models with efficient and delightful editor experiences. It’s intended for web developers who want to deliver better content experiences for their content teams and clients.