Documentación [ EN / ES ]

Introducción

¿Cómo funciona?

La integración se realiza creando una nueva instancia de la clase "Instabox3D", pasando un objeto con algunos parámetros de configuración. El configurador aparecerá en un iframe, dependiendo de dichos parámetros, como ventana emergente o dentro de un elemento HTML ya existente en la página web.

Incluir el script

La integración requiere la inclusión del siguiente script (como se muestra a continuación) cerca del final de sus páginas HTML.

<script src="https://www.instabox3d.com/output/default/js/integration.js"></script>

Código JavaScript

Necesitaremos escribir código JavaScript y puede hacerse en un archivo JavaScript o directamente dentro de las etiquetas <script>.

Para estos ejemplos, se hará entre las etiquetas <script> mantener todo el código en un mismo archivo y simplificar así su lectura.

Además el código está acompañado de comentarios con explicaciones(no afectan a su funcionamiento):

<!-- Comentario en HTML -->
// Comentario en JavaScript

Integración básica

Creando la instancia

Para crear la instancia de la clase "Instabox3D" escribimos el siguiente código:

<script>
 // Crear la instancia
 const instabox = new Instabox3D({
  // incluiremos los parámetros aquí
 });
</script>

Parámetro ( client: String )

El primer parámetro que veremos hace referencia al nombre del cliente. Éste además es el único parámetro obligatorio para la instanciación.

El valor debe ser el nombre del subdominio en el que esté su Instabox 3D

Si la URL de su Instabox 3D es "https://mi-empresa.instabox3d.com", el valor de este parámetro será "mi-empresa".

Suele ser el nombre de la empresa, en minúsculas y sustituyendo los espacios por guiones en caso de que los haya.

En estos ejemplos el valor será "demo"

Parámetro ( productRef: String )

Para que el configurador muestre el producto deseado es necesario especificar la referencia del producto.

La referencia de cada producto es la que se haya especificado en el briefing durante la fase de setup del configurador.

Este parámetro se puede especificar:

  • En el momento de la instanciación. En cuyo caso el configurador se abrirá mostrando el producto especificado.
  • En la ejecución del método open (explicado en la sección de métodos). En cuyo caso el configurador no se abrirá hasta el momento de la ejecución del mismo.

En estos ejemplos el valor será "fefco-0201"

Ejemplo de integración básica

Si al código que ya teníamos le añadimos los dos parámetros que acabamos de explicar, deberíamos ver el configurador como una ventana emergente a pantalla completa:

<!-- Incluir el script -->
<script src="https://www.instabox3d.com/output/default/js/integration.js"></script>

<script>
 // Crear la instancia
 const instabox = new Instabox3D({
  client: "demo",
  productRef: "fefco-0201",
 });
</script>

Modo depuración ( debug: Boolean = false )

Si has seguido los pasos y copiado el código anterior no deberías haber tenido ningún tipo de problema. Sin embargo, si te has animado a añadir tus propios valores (para "client" y "productRef") y algo no ha ido bien, no te preocupes porque esto te ayudará:

Si el parámetro debug (por defecto false) es true, imprime los errores que puedan ocurrir durante el proceso de integración.

Resulta muy útil activar este modo durante la fase de desarrollo para detectar posibles problemas, pero es aconsejable desactivarlo en entorno de producción.

<!-- Incluir el script -->
<script src="https://www.instabox3d.com/output/default/js/integration.js"></script>

<script>
 // Crear la instancia
 const instabox = new Instabox3D({
  client: "demo",
  productRef: "fefco-0201",
  debug: true,
 });
</script>

Personalizando el tamaño de la ventana emergente

Parámetro ( modal: Boolean = true)

Como hemos dicho anteriormente en la introducción, el configurador puede aparecer como una ventana emergente o dentro de un elemento HTML de la página web.

Para controlar este comportamiento se define el parámetro modal (por defecto true).

Como en este apartado trata de la personalización del modal, dejaremos el código tal y como está, ya que no definir este parámetro es lo mismo que poner modal: true.

Parámetro ( modalWidth: String = "100vw")

Por defecto el configurador aparece a pantalla completa, porque el valor por defecto de modalWidth es "100vw".

Bastaría con asignar en una cadena de texto (siguiendo la sintaxis de CSS) el valor deseado para cambiar la anchura.

Parámetro ( modalHeight : String = "100vh")

Similar a modalWidth, controla la altura de la ventana emergente con un valor por defecto de "100vh".

De nuevo, bastaría con asignar en una cadena de texto (siguiendo la sintaxis de CSS) el valor deseado para cambiar la altura.

Ejemplo al 80% de la pantalla

Agregando estos parámetros deberíamos ver de nuevo el configurador como una ventana emergente, pero esta vez, al 80% de la pantalla.

<!-- Incluir el script -->
<script src="https://www.instabox3d.com/output/default/js/integration.js"></script>

<script>
 // Crear la instancia
 const instabox = new Instabox3D({
  client: "demo",
  productRef: "fefco-0201",
  debug: true,
  modalWidth: "80vw",
  modalHeight: "80vh",
 });
</script>

Configurador dentro de un elemento HTML

Parámetro ( modal: Boolean = true )

Anteriormente explicábamos el parámetro modal con su valor por defecto true.

Como primer paso para que el configurador aparezca dentro de un elemento HTML, se ha de asignar false a este parámetro.

Parámetro ( containerId: String )

Cuando modal es false, es necesario definir el id del elemento HTML que servirá de contenedor para el configurador.

Parámetro ( iframeWidth : String = "100%" )

Una vez hemos definido el id del elemento contenedor, se puede definir el tamaño del configurador relativo a él.

Por defecto el valor es "100%" por lo que ocupará el total del ancho del elemento padre.

Bastaría con asignar en una cadena de texto (siguiendo la sintaxis de CSS) el valor deseado para cambiar la anchura relativa al elemento contenedor.

Parámetro ( iframeHeight : String = "600px" )

Similar a iframeWidth, iframeHeight controla la altura del configurador en relación al elemento contenedor.

Por defecto el valor es "600px" por lo que ocupará 600 píxeles de altura.

Bastaría con asignar en una cadena de texto (siguiendo la sintaxis de CSS) el valor deseado para cambiar la altura relativa al elemento contenedor.

Ajustando al elemento contenedor

Uno de los casos más comunes es el de ajustar el tamaño del iframe según el tamaño del elemento padre.

Este será el caso en el ejemplo que se muestra a continuación, y en el que:

  • No se define iframeWidth porque ya es 100% por defecto.
  • Se define iframeHeight: "auto".
  • Se le añade display: flex; al estilo del elemento contenedor.
<!-- Elemento HTML contenedor con id y estilo (incluido el display: flex;) -->
<div id="configurator-container" style="width: 75vw; height: 75vh; border: 1px solid black; display: flex;"></div>

<!-- Incluir el script --> <script src="https://www.instabox3d.com/output/default/js/integration.js"></script> <script>  // Crear la instancia  const instabox = new Instabox3D({   client: "demo",   productRef: "fefco-0201",   debug: true,   modal: false,   containerId: "configurator-container",   iframeHeight: "auto",  }); </script>

Recuperando los datos de la configuración

Parámetro / Evento (onFinish: Function)

Una vez el usuario finaliza la configuración se guardan los datos en la página de leads del Instabox, pero puede ser interesante recoger los datos, ya sea para mostrar un resumen, calcular un precio, guardar en base de datos, etc.

Para eso existe el parámetro onFinish, (de tipo función) que se ejecuta cuando el usuario finaliza la configuración pasando como parámetro un objeto JavaScript con los datos de dicha configuración.

Ejemplo recuperando datos

Si a cualquiera de los códigos anteriores le añadimos el parámetro onFinish, ya estaremos listos para recibir los datos de la configuración.

En este caso simplemente se mostrarán en la consola los datos, por lo que utilizaré una función anónima, pero se puede declarar una función y pasarla como valor de este parámetro sin ningún problema:

<!-- Incluir el script -->
<script src="https://www.instabox3d.com/output/default/js/integration.js"></script>

<script>
 // Crear la instancia
 const instabox = new Instabox3D({
  client: "demo",
  productRef: "fefco-0201",
  debug: true,
  modalWidth: "80vw",
  modalHeight: "80vh",
  onFinish: data => console.log("Datos del configurador", data),
 });
</script>

Estructura de los datos devueltos

El objeto contendrá los siguientes valores:

  • title: título o nombre del producto
  • image: url de la imagen del producto personalizado
  • instaviewer: url de la visualización 3D del producto personalizado
  • pdf: url del pdf con la información elegida en la configuración
  • artwork: url del archivo .zip que contiene las gráficas originales y un archivo .pdf por cada parte (a la que el usuario haya aplicado al menos una gráfica) con la posición de dichos archivos. Este valor no será devuelto si el usuario no ha aplicado ninguna gráfica al producto.
  • config: objeto JavaScript en el que aparecerá cada variable como una propiedad, acompañada de su valor

Al igual que la referencia del producto, los nombres de las variables serán los que se hayan especificado en el briefing durante la fase de setup del configurador.

Ejemplo de datos devueltos:
{
 title: "Título del producto",
 image: "https://example.instabox3d.com/files/image.png",
 instaviewer: "https://example.instabox3d.com/viewer/example",
 pdf: "https://example.instabox3d.com/files/summary.pdf",
 artwork: "https://example.instabox3d.com/files/artwork.zip",
 config: {
  variable1: 300,
  variable2: 200,
  variable3: 100
 }
}

Asignando valores por defecto a la caja (solo paramétricas)

Casos de uso

En el caso de las cajas paramétricas es posible asignar los valores por defecto a las variables. Por ejemplo para hacer que la caja aparezca con unas medidas determinadas.

Otro caso muy común es el de las cajas fijas creadas a partir de modelos paramétricos, es decir, se crea una única caja paramétrica y luego en la integración se pasan las medidas de la caja fija en cuestión.

Parámetro ( boxParams: Object )

El parámetro boxParams (de tipo objeto) es el encargado de recoger las variables por defecto de la caja, estableciendo el nombre de la variable como clave y su valor deseado.

De nuevo, los nombres de las variables serán los que se hayan especificado en el briefing durante la fase de setup del configurador.

En este caso, la caja que se está utilizando tiene las siguientes variables:

  • l: largo en mm
  • b: ancho en mm
  • h: alto en mm

Entonces podríamos crear el siguiente objeto:

{
 l: 320,
 b: 270,
 h: 150
}

Y si añadimos esto al código deberíamos ver como ahora la caja inicia con esos valores:

<!-- Elemento HTML contenedor con id -->
<div id="configurator-container" style="width: 75vw; height: 75vh; border: 1px solid black; display: flex;"></div>

<!-- Incluir el script --> <script src="https://www.instabox3d.com/output/default/js/integration.js"></script> <script>  // Crear la instancia  const instabox = new Instabox3D({   client: "demo",   productRef: "fefco-0201",   debug: true,   modal: false,   containerId: "configurator-container",   iframeHeight: "auto",   boxParams: {    l: 320,    b: 270,    h: 150,   },  }); </script>

Métodos open y close

Casos de uso

Es bastante común que se necesite abrir el configurador tras alguna acción del usuario, como por ejemplo, tras pulsar un botón.

Retomando lo que habíamos dicho en la explicación del parámetro productRef, dicho parámetro se puede especificar en el momento de la instanciación o en el método open.

En el caso que estábamos comentando de abrir el configurador tras una acción, no tiene sentido definir el productRef en la instanciación porque esto haría que el configurador se abriese en ese momento, y no es lo que queremos.

Método open

Para abrir el configurador de forma manual, se ha de ejecutar el método open, pasando como parámetro un objeto de configuración que contenga el parámetro productRef

Cabe destacar que en el argumento (de tipo Object) se pueden definir otros parámetros además del de productRef, sobrescribiendo los valores antiguos en caso de que ya fuesen definidos en el momento de la instanciación.

Método close

Si una vez abierto el configurador queremos dar la opción al usuario de salir sin finalizar, lo más lógico es tener algún tipo de interacción para cerrar el configurador. Esto es posible ejecutando el método close que no recibe ningún argumento.

Implementando botones

Utilizando los conceptos explicados anteriormente implementaremos la integración con botones para abrir y cerrar el configurador.

En este caso no se pasará el parámetro productRef en el momento de la instanciación, sino que se pasará en el momento de ejecutar el método open.

Antes de ejecutar los métodos se debe comprobar si la instanciación está lista con la siguiente expresión:
if (instabox.isReady) {
 // ejecutar métodos
}
Profundizaremos más en este tema en el apartado de Carga asíncrona y tratamiento de errores.

Para mantener el código limpio y sencillo crearemos dos funciones, una para abrir y otra para cerrar el configurador y en ellas se ejecutará el método correspondiente:

<!-- Elemento HTML contenedor con id y estilo (incluido el display: flex;) -->
<div id="configurator-container" style="width: 75vw; height: 75vh; border: 1px solid black; display: flex"></div>

<!-- Botón que ejecuta la función openConfigurator para abrir el configurador --> <button onclick="openConfigurator()">Abrir configurador</button>

<!-- Botón que ejecuta la función closeConfigurator para cerrar el configurador --> <button onclick="closeConfigurator()">Cerrar configurador</button>

<!-- Incluir el script --> <script src="https://www.instabox3d.com/output/default/js/integration.js"></script> <script>  function openConfigurator() {   if (instabox.isReady) {    instabox.configurator.open({     productRef: "fefco-0201"    });   }  }  function closeConfigurator() {   if (instabox.isReady) {    instabox.configurator.close();   }  }  // Crear la instancia sin productRef para que no abra el configurador  const instabox = new Instabox3D({   client: "demo",   debug: true,   modal: false,   containerId: "configurator-container",   iframeHeight: "auto",  }); </script>

Carga asíncrona y tratamiento de errores con Callbacks

Carga y errores

Es hora de entrar en temas un poco más avanzados. En el apartado de métodos comentamos la necesidad de comprobar si el instabox está listo antes de ejecutar cualquier método, pero ¿por qué?

Porque el proceso de carga es asíncrono, es decir, el código se sigue ejecutando y el usuario sigue pudiendo interactuar con la página mientras el Instabox está cargando. Esto puede llevar a que se ejecute un método antes incluso de que haya cargado por completo, ya sea porque el usuario ha clicado en un botón o porque se ha definido así en el código.

Con esta simple comprobación se evitan posibles problemas pero, puede ser interesante saber cuando ha terminado de cargar para realizar alguna acción, o incluso saber si no ha podido cargar con éxito.

Para eso hay dos formas:

  • con callbacks
  • con promises

Carga y errores con callbacks #1

Primero trataremos el caso en el que se define el parámetro productRef en el momento de instanciación.

El constructor de la clase Instabox3D recibe dos parámetros opcionales además del objeto de configuración:

  • El segundo parámetro es una función callback que se ejecutará en el momento en el que se haya instanciado correctamente y el configurador haya terminado de cargar.
  • El tercer parámetro es una función callback que se ejecutará en caso de error, pasando como parámetro un mensaje de error.

Para este ejemplo:

  • Se define el objeto de configuración previamente para más claridad en el código
  • Se crean dos funciones que simplemente muestran mensajes en la consola.
  • No se activa el modo debug ya que estamos mostrando posibles errores con la función onInstaboxError
<!-- Elemento HTML contenedor con id -->
<div id="configurator-container" style="width: 75vw; height: 75vh; border: 1px solid black; display: flex"></div>

<!-- Incluir el script --> <script src="https://www.instabox3d.com/output/default/js/integration.js"></script> <script>  function onInstaboxReady() {   console.log("Instabox is ready");  }  function onInstaboxError(error) {   console.warn(error);  }  // Objeto de configuración  const configObject = {   client: "demo",   productRef: "fefco-0201",   modal: false,   containerId: "configurator-container",   iframeHeight: "auto",  };  // Crear la instancia con callbacks  const instabox = new Instabox3D(configObject, onInstaboxReady, onInstaboxError); </script>

Carga y errores con callbacks #2

Tratemos ahora el caso en el que no se define el parámetro productRef en el momento de instanciación.

Como ya sabemos, en este caso no se abrirá el configurador hasta que se ejecute el método open con el productRef deseado, por lo que las funciones callback que hemos definido en el ejemplo anterior servirán para saber cuando se ha instanciado o, en su defecto, si ha ocurrido un error.

Entonces, ¿Cómo sabemos cuando el configurador se ha abierto y ha terminado de cargar?

Pues el método open también recibe dos parámetros opcionales además del objeto de configuración:

  • El segundo parámetro es una función callback que se ejecutará en el momento en el que el configurador haya terminado de cargar.
  • El tercer parámetro es una función callback que se ejecutará en caso de error, pasando como parámetro un mensaje de error.

En este ejemplo:

  • No se añade el productRef en la instanciación
  • Se añade la implementación de los botones
  • Se crea una función para cuando el configurador ha cargado correctamente
  • Se utiliza la misma función de error para el configurador y para la instanciación
<!-- Elemento HTML contenedor con id -->
<div id="configurator-container" style="width: 75vw; height: 75vh; border: 1px solid black; display: flex"></div>

<!-- Botón que ejecuta la función openConfigurator para abrir el configurador --> <button onclick="openConfigurator()">Abrir configurador</button>

<!-- Botón que ejecuta la función closeConfigurator para cerrar el configurador --> <button onclick="closeConfigurator()">Cerrar configurador</button>

<!-- Incluir el script --> <script src="https://www.instabox3d.com/output/default/js/integration.js"></script> <script>  function openConfigurator() {   if (instabox.isReady) {     // Abrir el configurador con calbacks    instabox.configurator.open(     { productRef: "fefco-0201" },     onConfiguratorReady,     onInstaboxError    );   }  }  function closeConfigurator() {   if (instabox.isReady) {    instabox.configurator.close();   }  }  function onInstaboxReady() {   console.log("Instabox is ready");  }  function onInstaboxError(error) {   console.warn(error);  }  function onConfiguratorReady() {   console.log("Configurator is ready");  }  // Objeto de configuración  const configObject = {   client: "demo",   modal: false,   containerId: "configurator-container",   iframeHeight: "auto",  };  // Crear la instancia con callbacks  const instabox = new Instabox3D(configObject, onInstaboxReady, onInstaboxError); </script>

Carga y errores con Promises #1

Volvamos al caso en el que se define el parámetro productRef en el momento de instanciación, pero esta vez con promesas.

El código es prácticamente igual pero esta vez necesitamos añadir un parámetro que no habíamos visto hasta ahora:

Parámetro ( autoInit: Boolean = true )

Este parámetro se utiliza para poder iniciar manualmente la carga en el caso que queramos gestionar la parte asíncrona con promesas.

En este ejemplo:

  • Se define el parámetro autoInit con el valor false
  • Se inicia manualmente con el método init que devuelve una promesa
  • Se gestiona la promesa (en este caso con un then y catch, pero podría ser perfectamente con un async / await y su correspondiente try ... catch)
<!-- Elemento HTML contenedor con id -->
<div id="configurator-container" style="width: 75vw; height: 75vh; border: 1px solid black; display: flex"></div>

<!-- Incluir el script --> <script src="https://www.instabox3d.com/output/default/js/integration.js"></script> <script>  function onInstaboxReady() {   console.log("Instabox is ready");  }  function onInstaboxError(error) {   console.warn(error);  }  // Objeto de configuración  const configObject = {   client: "demo",   productRef: "fefco-0201",   modal: false,   containerId: "configurator-container",   iframeHeight: "auto",   autoInit: false,  };  // Crear la instancia  const instabox = new Instabox3D(configObject);  // Iniciar manualmente con promesas  instabox.init().then(onInstaboxReady).catch(onInstaboxError); </script>

Carga y errores con Promises #2

En el caso en el que no se define el parámetro productRef en el momento de instanciación, también se puede manejar la parte asíncrona con promesas, ya que el método open devuelve una.

En este ejemplo:

  • No se añade el productRef en la instanciación
  • Se añade la implementación de los botones
  • Se crea una función para cuando el configurador ha cargado correctamente
  • Se utiliza la misma función de error para el configurador y para la instanciación
  • Se gestiona la promesa (en este caso con un then y catch, pero podría ser perfectamente con un async / await y su correspondiente try ... catch)
<!-- Elemento HTML contenedor con id -->
<div id="configurator-container" style="width: 75vw; height: 75vh; border: 1px solid black; display: flex"></div>

<!-- Botón que ejecuta la función openConfigurator para abrir el configurador --> <button onclick="openConfigurator()">Abrir configurador</button>

<!-- Botón que ejecuta la función closeConfigurator para cerrar el configurador --> <button onclick="closeConfigurator()">Cerrar configurador</button>

<!-- Incluir el script --> <script src="https://www.instabox3d.com/output/default/js/integration.js"></script> <script>  function openConfigurator() {   if (instabox.isReady) {     // Abrir el configurador con promesas    instabox.configurator     .open({ productRef: "fefco-0201" })     .then(onConfiguratorReady)     .catch(onInstaboxError);   }  }  function closeConfigurator() {   if (instabox.isReady) {    instabox.configurator.close();   }  }  function onInstaboxReady() {   console.log("Instabox is ready");  }  function onInstaboxError(error) {   console.warn(error);  }  function onConfiguratorReady() {   console.log("Configurator is ready");  }  // Objeto de configuración  const configObject = {   client: "demo",   modal: false,   containerId: "configurator-container",   iframeHeight: "auto",   autoInit: false,  };  // Crear la instancia  const instabox = new Instabox3D(configObject);  // Iniciar manualmente con promesas  instabox.init().then(onInstaboxReady).catch(onInstaboxError); </script>

Comunicación bidireccional

Casos de uso

Hemos llegado al último apartado y quizá el más potente, en el que veremos como establecer una comunicación bidireccional fluida.

Esto permitirá entre otras cosas, calcular precios dinámicamente (sin esperar a que el usuario finalice la configuración) o controlar los inputs de forma externa al configurador y por lo tanto, hacer validaciones o aplicar estilos al gusto.

Parámetro / Evento (onChange: Function)

Cada vez que el usuario realiza un cambio en la configuración se ejecuta esta función pasando como parámetro un array con las variables de la caja, incluyendo lo valores actuales y valores disponibles en caso de variables de selección.

Ejemplo de variable de selección:
{
 name: "mat",
 options: [
  {name: "Material 1", value: 0}
  {name: "Material 2", value: 1}
  {name: "Material 3", value: 2}
 ],
 publicName: "Material",
 type: "SelectVariable",
 value: 0
}
Ejemplo de variable numérica:
{
 name: "l",
 publicName: "Length",
 type: "Variable",
 value: 350
}

Método changeBoxParams

El método changeBoxParams funciona de forma similar al parámetro boxParams, y se puede ejecutar pasando un objeto que tendrá el nombre de la variable como clave y su valor deseado.

Los nombres de las variables serán los que se hayan especificado en el briefing durante la fase de setup del configurador.

En este caso, la caja que se está utilizando tiene las siguientes variables:

  • l: largo en mm
  • b: ancho en mm
  • h: alto en mm

Entonces podríamos enviar el siguiente objeto con el método changeBoxParams para cambiar el valor del largo dinámicamente:

{
 l: 320;
}

Método openArtwork

El método openArtwork se puede utilizar para abrir el editor 2D, donde el usuario podrá subir y colocar gráficas sobre la caja.

Parámetro / Evento (onArtworkOpened: Function)

Cuando se abre el editor 2D se ejecuta esta función

Método closeArtwork

El método closeArtwork se puede utilizar para cerrar el editor 2D.

Parámetro / Evento (onArtworkClosed: Function)

Cuando se cierra el editor 2D se ejecuta esta función

Método finishConfiguration

El método finishConfiguration se puede utilizar para finalizar la configuración en cualquier momento.

Ejemplo de integración bidireccional

En este ejemplo:

  • Se añade un input para definir el largo de forma externa al configurador
  • Se recogen los valores actuales de la caja para mostrarlos en el input
  • Se añade un botón para finalizar la configuración de forma externa al configurador
<!-- Elemento HTML contenedor con id -->
<div id="configurator-container" style="width: 75vw; height: 75vh; border: 1px solid black; display: flex"></div>

<!-- Input para modificar el largo de la caja --> <input id="length" type="number" placeholder="Length" onchange="changeBoxLength(this)" />

<!-- Botón que abre o cierra el editor 2D --> <button id="artwork" onclick="openArtworkEditor()">Abrir Editor 2D</button>

<!-- Botón que ejecuta la función finishConfiguration para finalizar la configuración --> <button onclick="finishConfiguration()">Finalizar configuración</button>

<!-- Incluir el script --> <script src="https://www.instabox3d.com/output/default/js/integration.js"></script> <script>  function changeBoxLength(input) {   if (instabox.isReady) {    instabox.configurator.changeBoxParams({     l: input.value    });   }  }  function onInstaboxChange(data) {   const variable = data.find(variable => variable.name === "l");   if (variable) {    document.getElementById("length").value = variable.value;   }  }  function finishConfiguration() {   if (instabox.isReady) {    instabox.configurator.finishConfiguration();   }  }  function openArtworkEditor() {   if (instabox.isReady) {    instabox.configurator.openArtwork();   }  }  function closeArtworkEditor() {   if (instabox.isReady) {    instabox.configurator.closeArtwork();   }  }  function onArtworkOpened() {   const artworkElement = document.getElementById("artwork");   artworkElement.innerHTML = "Cerrar Editor 2D";   artworkElement.onclick = closeArtworkEditor;  }  function onArtworkClosed() {   const artworkElement = document.getElementById("artwork");   artworkElement.innerHTML = "Abrir Editor 2D";   artworkElement.onclick = openArtworkEditor;  }  // Crear la instancia  const instabox = new Instabox3D({   client: "demo",   productRef: "fefco-0201",   modal: false,   containerId: "configurator-container",   iframeHeight: "auto",   debug: true,   onChange: onInstaboxChange,   onArtworkOpened: onArtworkOpened,   onArtworkClosed: onArtworkClosed,  }); </script>