TrainBeyond — Propuesta Interactiva / Interactive Proposal
---
ESPAÑOL
1. Qué es
La propuesta interactiva es la propuesta comercial de TrainBeyond convertida en una experiencia: una página web privada por cliente donde una presentadora virtual con voz recorre la propuesta sección por sección, responde preguntas en vivo, y donde el cliente entra a una escena 3D de su propia planta u operación para ver, de pie y a escala real, lo que el entrenamiento le va a dar. La misma página funciona en computadora, teléfono, visor de realidad virtual (Meta Quest) y, con passthrough, en realidad aumentada dentro de la sala del cliente.
Todo sale de tres cosas:
| Pieza | Quién la hace | Con qué |
|---|---|---|
| El texto de la propuesta | ventas, con ayuda de la IA | fuentes del cliente en Google Drive + un Google Doc editable |
| La escena 3D (opcional pero es lo que vende) | el equipo de diseño 3D | un archivo .blend o .fbx con las convenciones de nombres de este documento |
| La publicación | operaciones | comandos en Google Chat (/gen-proposal, /audit-showcase) |
El resultado es una URL estable por unidad (código de 3 letras, p. ej. FCA) protegida por un código de acceso que se le da al cliente. Republicar sobrescribe esa misma URL.
La capacitación de una unidad como aplicación propia (el player de capacitación en DEMO, con su pantalla del módulo, sus ejercicios y el LMS) tiene su propia documentación: Player de capacitación.
2. Qué ve y hace el cliente
2.1 Entrar
El cliente abre el enlace y escribe su código de acceso (dura 180 días; el navegador lo recuerda 7 días). Dentro, la galería muestra los paneles de la propuesta en un anillo alrededor de una maqueta de la escena, y la presentadora empieza a hablar.
2.2 La presentación y la guía de voz
- La presentadora recorre las secciones; el cliente puede pausar y hacer preguntas en voz alta (botón de micrófono). Responde con lo que sabe de la propuesta y de los materiales de la unidad.
- Dentro de la escena habla la misma voz, pero en su propia sesión: la de la instructora, que no conoce la propuesta comercial (sin secciones, presupuesto ni videos de ejemplo; solo el material del cliente y la configuración de la escena) y nunca vende. Al entrar se cierra la sesión de la presentadora y se abre la suya; al salir se cierra la suya y la presentación vuelve como estaba: en pausa en su lámina (▶ la continúa) o con sus preguntas abiertas. La instructora: explica cada estación al llegar, señala objetos, invita a probar las interacciones. Nunca se interrumpe a sí misma: lo que pasa mientras habla se lo cuenta al terminar. Si el visitante se detiene a observar algo, ella lo toma en cuenta pero no comenta por su cuenta.
?browseal final de la dirección abre la propuesta sin presentación, con la guía disponible para preguntas.- Presentadora en video. Por unidad, la presentadora puede verse como video real (el avatar Kira de Gemini Live) en una tarjeta en la esquina inferior izquierda, en la galería y dentro de la escena, en lugar del personaje 3D. Se activa al publicar con
--video, o en cualquier momento con Ctrl+Shift+V dentro de la propuesta (queda guardado para esa unidad y la sesión de voz se reinicia). Sin video, la presentadora 3D sigue siendo la opción de respaldo.
2.3 Dentro de la escena
La visita es un ejercicio por tareas: las estaciones, en su orden, son las tareas. La instrucción de cada una es la nota de la estación, y lo que hay que hacer ahí son los objetos interactivos junto a ella (el hotspot, la hoja, la persona, la pantalla, los controles). La guía pide una tarea a la vez, al llegar explica la estación y dice qué hacer, confirma cada tarea cumplida, da una pista cuando el cliente se atasca y cierra con una retroalimentación. La lista aparece a la derecha, con las hechas tachadas; se pueden hacer en cualquier orden. (El panel de ajustes permite volver al recorrido narrado o dar la tarea por hecha solo con llegar.)
Lecciones. Cada estación tiene una lección escrita al publicar a partir del material del cliente y de la configuración de la escena, con su infografía. Al llegar, la guía la enseña completa, una parte por turno; con infografías, cada una aparece al nombrarla. El botón Lección de la lista hace que la guía la enseñe otra vez desde el principio, sin cambiar ninguna tarea. Las preguntas de la revisión salen de esa misma lección.
Pantalla de inicio. Al entrar al ejercicio (y tras reiniciarlo) aparece una pantalla con la frase de bienvenida, la misión (las tareas en orden, con el número y nombre de su estación) y los controles, con su propia música. La guía calla al instante al abrirse (también si venía hablando) y no dice nada hasta que se cierra: un clic en cualquier parte de la pantalla, o sola a los tres minutos (ajuste).
Evaluación. Al terminar cada tarea, la guía hace dos preguntas cortas sobre esa estación, sacadas de lo que acaba de enseñar (el material de la propuesta y la configuración de la escena). Cuando ella termina de preguntar aparece una tarjeta en el centro de la pantalla con sus palabras, una línea para escribir la respuesta y un botón No sé; mientras la revisión está abierta el cliente no puede caminar ni activar nada. Responde de viva voz (el micrófono se abre al terminar la pregunta) o escribiendo; ella califica cada respuesta de 0 a 100 y la lista muestra la calificación de cada pregunta y el promedio de la estación ("100 · 0 → 50 %", verde si aprueba, rojo si no). Una calificación cuenta solo después de que el cliente haya hablado o escrito; si la guía califica antes, esa nota se descarta y repite la pregunta. Mientras la revisión está abierta, nada más llega a la guía. Una pregunta sin respuesta en tres minutos vale 0 y se pasa a la siguiente. Tras cada respuesta ella dice cuál era la correcta y por qué: una frase si acertó, dos si falló. La rúbrica (100 completa y correcta · 80 una omisión menor · 60 la idea principal · 30 relacionada pero incorrecta · 0 incorrecta o sin respuesta; solo contra el material de la propuesta) y todas las instrucciones que la página le da a la guía están en el panel de ajustes, grupo "Instrucciones a la guía", y se guardan por unidad. La tarjeta aparece cuando la acción terminó por completo y ella acabó de preguntar. Al accionar un punto interactivo, la guía dice en una frase qué acaba de hacer el cliente y confirma que quedó hecho. Mientras dura la acción, un recuadro muestra de cerca el instrumento o pieza que la animación mueve, para leer su valor; si el punto trae una nota con la lectura, ella la dice al terminar. Con todas las tareas hechas y revisadas viene el examen: el cliente repite todo el ejercicio solo, en el orden correcto, sin lista, sin números de estación y sin ayuda; la guía guarda silencio hasta el final. Llegar a una estación es acercarse a ella caminando (o con su marcador, fuera del examen); la estación donde empieza el examen cuenta solo después de alejarse y volver. Se aprueba completando todas las tareas con al menos el 70 % en su orden y con el promedio de las revisiones de las estaciones en o sobre esa misma nota mínima (ajuste checksCount; apagado, decide solo la práctica). El informe muestra las dos partes con su propio resultado. Al terminar, ella cierra con el resultado del examen, el de las revisiones y una retroalimentación breve, y se abre el informe del examen: aprobado o no, tareas en orden, tiempo, y la calificación de la revisión de cada estación con su promedio (verde aprueba, rojo no); suena la música de éxito o de fallo mientras el informe está abierto. Desde el informe se cierra o se reinicia el ejercicio; el botón Informe del resultado lo vuelve a abrir. Si el cliente sale de la escena con el informe abierto y vuelve a entrar, el informe aparece de nuevo, con Cerrar y Reiniciar; si recarga la página, el ejercicio empieza de cero. (Preguntas por estación, examen y nota mínima se ajustan en el panel.) El informe final ocupa casi toda la pantalla, en tres pestañas: Resumen (resultado, nota y nota por estación), Plan de estudio para el siguiente intento, que la página arma con las propias láminas (por cada pregunta fallada: la lámina que la enseña, citada, y qué hacer en la escena: repetir esa lámina con el botón Lección y pulsar los objetos de la estación), y Preguntas y respuestas (cada pregunta con tu respuesta, la correcta, el comentario y la frase de la lección que la enseña). El botón Descargar PDF guarda el mismo informe como archivo PDF; la casilla «Incluir la transcripción completa de la sesión en el PDF» (desmarcada por defecto) añade al final del PDF todo el diálogo de la sesión, con las líneas que tratan los temas del plan de estudio resaltadas y el tema indicado debajo. Al cerrar el informe, los datos del ejercicio se conservan en el navegador: en el panel de configuración (Ctrl+Shift+K), «Informe: datos guardados» permite abrir de nuevo el último informe, guardar los datos en un archivo y cargar un informe desde un archivo, sin repetir el ejercicio.
El micrófono dentro de la escena tiene dos estados, abierto y cerrado, y la insignia de arriba a la derecha dice cuál. Se abre solo cuando la guía escucha: unos segundos después de cada intervención suya, y mientras el cliente siga hablando. Caminando, con una hoja abierta o mientras ella explica está cerrado: el ruido de la sala no le llega. Para hablarle en cualquier otro momento, mantén pulsada la tecla M o haz clic en la insignia. En el visor VR no hay teclado ni insignia: se mantiene pulsado A o X en cualquiera de los controles, y un letrero bajo la vista dice si el micrófono está abierto ("Te escucha") o cómo abrirlo. Mientras una pregunta de revisión espera la respuesta, en el visor ella escucha entre sus turnos sin tener que pulsar nada (en VR no hay dónde escribir la respuesta).
| Acción | Computadora | Visor VR |
|---|---|---|
| Entrar a la escena | clic en la maqueta | botón Enter VR |
| Mirar | arrastrar con el ratón | girar la cabeza |
| Caminar | flechas (el suelo se sigue: escalones, rampas; paredes, postes y máquinas detienen al visitante) | palanca; teletransporte apuntando al suelo |
| Cambiar de estación | clic en el marcador numerado: el personaje camina hasta allí rodeando los obstáculos | apuntar al marcador y gatillo |
| Empezar de nuevo | botón Reiniciar en la lista de tareas o en el informe: todo vuelve al inicio (tareas, puntos accionados, hojas, pantallas, posición en la estación 1) y la entrada se repite: pantalla de inicio, bienvenida y lección (pide confirmación) | igual |
| Reportar un problema | Ctrl+Shift+L copia el id de la sesión y marca el momento en el registro; envíalo con lo que pasó | igual |
| Saltar a la revisión (pruebas) | Ctrl+Shift+X termina la lección de la estación en curso, da su tarea por hecha y abre la revisión | igual |
| Saber dónde estás | la barra de estado muestra el número y el nombre de la estación ("Estación 1 · Placa"); el marcador de la estación donde estás se ve gris y quieto mientras su tarea esté pendiente; la guía nombra las estaciones por su número, como los marcadores | igual |
| Vista de pájaro | barra espaciadora | — |
| Cambiar de vista (tercera / primera persona / dron) | V | — |
| Activar un punto interactivo cercano | E, o clic en el rombo | gatillo sobre el rombo |
| Pasar imagen en una pantalla | clic en la pantalla | gatillo |
| Hablar con un personaje | E cerca de él, o clic | gatillo |
| Hablarle a la guía | se abre sola tras cada intervención suya; en otro momento, mantener M o clic en la insignia | se abre sola tras cada intervención suya y durante toda una pregunta de revisión; en otro momento, mantener A o X |
| Pulsar un botón / girar una perilla / mover una palanca de la máquina | clic / arrastrar o rueda / arrastrar | gatillo / gatillo sostenido y subir o bajar la mano o usar el stick / gatillo sostenido y el stick |
| Abrir un formulario | clic en el portapapeles: la cámara se acerca y la página aparece sola sobre él | se llena desde un teléfono (?clipboard) |
| Salir | Esc. Al volver a entrar, el visitante aparece en la estación donde estaba y el avance del ejercicio se conserva; Reiniciar lo devuelve a la estación 1 | — |
Con un Avatar entregado, el cliente recorre la escena como un personaje (tercera persona por defecto); en VR ve su propio cuerpo del cuello hacia abajo y, con manos rastreadas, sus manos reales mueven las del avatar.
2.4 Direcciones especiales
| Dirección | Para qué |
|---|---|
https://…/FCA/ | la propuesta |
https://…/FCA/?clipboard | en un teléfono o tableta: los formularios de la escena, para llenarlos mientras otro los ve en el visor |
https://…/FCA/?display | en una computadora: comparte su pantalla hacia los monitores Display_ de la escena (misma red) |
https://…/FCA/?browse | sin presentación; solo la escena y la guía |
2.5 Realidad aumentada
En un visor con passthrough, Ver en tu sala (RA) coloca la maqueta sobre una mesa real. Con un personaje entregado (--character), el botón Practicar en tu sala (RA) pone a esa persona a tamaño real en la sala del cliente, con una pantalla delante, para practicar una conversación.
3. Cómo se produce una propuesta
3.1 Fuentes en Google Drive
Cada unidad tiene su carpeta bajo la raíz de ventas (Sales Drive). Lo que hay ahí alimenta el texto, la guía y la escena:
| Qué | Dónde / cómo se reconoce | Para qué sirve |
|---|---|---|
| Documentos del cliente, notas de reunión, imágenes | carpetas de la unidad; la carpeta da la etiqueta (from-client, meeting-notes…) | el borrador de la propuesta y el contexto de la guía |
| Configuración de la escena | un archivo TOML cuyo nombre contenga scene config o configuración de la escena | los ajustes de la unidad, una tabla por objeto de la escena y las instrucciones de la guía (ver el capítulo 10) |
| Escena 3D | el archivo que se pasa a --showcase | la maqueta y la vista interior |
| Avatar presentador | carpeta con export FBX de Character Creator 4, pasada a --avatar | la presentadora en 3D |
| Personaje para practicar | archivos pasados a --character, --persona, --idle, --talk | una persona con la que el cliente conversa |
| Páginas de formularios | archivos .html en una carpeta forms o junto a los documentos del cliente | los portapapeles Clipboard_ de la escena |
| Videos de ejemplo | carpeta compartida video-samples / trainbeyond | la galería de ejemplos |
3.2 Los comandos
Se escriben en Google Chat, en el espacio de Flow Manager. CODIGO es el código de la unidad: 3 caracteres alfanuméricos.
Paso 1 — generar el borrador
/gen-proposal FCA --es
/gen-proposal FCA --es --high
Genera con IA un borrador y lo guarda como Google Doc "FCA Proposal" en la carpeta de ventas de la unidad. --es fija el idioma de la propuesta (el predeterminado es inglés); --high pide un borrador más completo. Volver a correr este paso regenera el Doc y borra las ediciones.
Paso 2 — editar el Doc
Lo que quede en el Doc es lo que se publica. Dentro de una sección se pueden poner líneas especiales:
<<panel-image: https://drive.google.com/file/d/1AbC.../view | Vista de la línea de corte>>
<<examples: https://drive.google.com/file/d/1Vid1.../view | https://drive.google.com/file/d/1Vid2.../view>>
<<examples-exclude: https://drive.google.com/file/d/1Vid3.../view>>
<<examples: none>>
<<panel-image: URL | Leyenda>>: una imagen de diseño en ese panel (archivo de Drive visible por enlace; una por sección).<<examples: …>>: deja solo esos videos de ejemplo, en ese orden;examples-excludeoculta los listados;examples: nonequita la galería.- Un salto de página real (Ctrl+Enter) controla la paginación impresa.
Paso 3 — publicar
/gen-proposal FCA --es --publish
/gen-proposal FCA --es --publish --interactive
Publica el Doc tal cual (sin IA). --interactive publica además la experiencia 3D con la presentadora en vivo. --video deja activada para esa unidad la presentadora en video (Kira); sin él, la presentadora 3D. Repite --es para que la narración y la guía hablen en el idioma correcto. La respuesta en el chat trae la URL y el código de acceso para el cliente.
La escena 3D
/audit-showcase https://drive.google.com/file/d/1AbC.../view --project FCA --es
/gen-proposal FCA --es --showcase https://drive.google.com/file/d/1AbC.../view
/gen-proposal FCA --es --publish --interactive --showcase https://drive.google.com/file/d/1AbC.../view
- Auditar primero (
/audit-showcase): abre el archivo entregado, lo revisa y reporta en el chat. Es de solo lectura: no convierte ni publica nada. Pasa el mismo--projectque la unidad. --showcasecon el enlace al.blend,.fbxo.glb(o a una carpeta con uno): convierte el archivo, lo aloja y lo pone como maqueta y vista interior.--redrawvuelve a dibujar infografías de las lecciones: solo (--redraw) oall, todas; una estación por nombre, etiqueta o número (--redraw placa,--redraw 1); una lámina (--redraw placa:2); varias separadas por comas (--redraw placa:2,mesa). Sin--publishrepublica la propuesta existente con la escena nueva; con--publish --interactivepublica todo junto.- Volver a entregar el mismo archivo sin cambios no reconvierte nada.
Avatar presentador
/gen-proposal FCA --es --avatar https://drive.google.com/drive/folders/1Fem.../
Carpeta de Drive con el export FBX de Character Creator 4. El nombre de la carpeta debe contener female o male: eso elige la voz. Sin --publish republica la propuesta existente con el avatar nuevo.
Personaje para practicar una conversación
/gen-proposal FCA --es --publish --interactive \
--character https://drive.google.com/file/d/1Alej.../view \
--persona https://docs.google.com/document/d/1Pers.../edit \
--idle https://drive.google.com/file/d/1Idle.../view \
--talk https://drive.google.com/file/d/1Talk.../view
--character: export de Character Creator 4 (.fbx, T-pose, sin animación; huesosCC_Base_*; un personaje de Mixamo se rechaza).--persona: Google Doc con líneasNombre:,Persona:,Líneas:,Voz:(oGénero:).Persona:yLíneas:abren secciones de varias líneas;Líneas:son los datos y frases que la persona dice palabra por palabra.--idle/--talk: clips.fbxde solo movimiento sobre el esqueleto de Character Creator (de Character Creator, iClone o ActorCore); un clip de Mixamo se reorienta al publicar. Son opcionales: sin ellos se usan los últimos clips importados.- Con escena, el objeto
Character_Alejandramarca dónde está; sin escena, la persona aparece en la sala del cliente (RA).
Ejemplo de Doc de persona:
Nombre: Alejandra
Género: Femenino
Persona: Recepcionista del hotel, 8 años en el puesto, amable pero firme con el protocolo.
Líneas:
Buenos días, bienvenido al Hotel Foliatti, ¿tiene reservación?
El check-in es a partir de las 15:00.
Otros
/gen-proposal --help
/audit-showcase --help
/flow status --project FCA
3.3 Qué devuelve una publicación
En el chat: fuentes usadas, trabajos de imagen, la URL de la propuesta interactiva y el código de acceso. Cada unidad tiene una sola URL; republicar la reemplaza en el momento, sin interrumpir a quien la tenga abierta.
4. Convenciones de nombres — referencia rápida
El visor no se configura: lee los nombres de los objetos y de las acciones del archivo de Blender. Lo que no coincide con ninguna convención es escenografía normal. Los nombres se comparan sin espacios sobrantes y sin distinguir mayúsculas; el separador puede ser _ o ..
| Nombre | Tipo | Qué hace | Ejemplo |
|---|---|---|---|
Station_NN_Nombre | empty en el piso | punto de pie; NN ordena; se entra por el menor; su −Y mira hacia el frente | Station_01_Recepcion, Station_02_Linea_De_Corte |
Seat_Nombre | empty a la altura de los ojos | punto sentado (cabina, silla de control); vista limitada | Seat_Cabina_Grua |
Skybox | malla (domo invertido) | el cielo y la luz ambiente; oculto en la maqueta | Skybox |
Sun | luz tipo Sun | dirección y color de las sombras (la intensidad la pone el visor) | Sun |
Loop_Nombre | acción | animación ambiental en ciclo mientras el cliente está dentro | Loop_Transportador, Loop_Antorcha |
Avatar + Idle, Walk | armature + acciones | el cliente recorre la escena como ese personaje | Avatar, Avatar_Eyes (empty opcional a la altura de los ojos) |
Hotspot_X / Play_X / Act_X | empty / acción de escena / clip del avatar | interacción: ancla donde se para, el equipo moviéndose, el gesto humano | Hotspot_Abrir_Valvula, Play_Abrir_Valvula, Act_Abrir_Valvula (Act_Operate = gesto genérico) |
Focus_Nombre | objeto o empty | lo que la maqueta encuadra cuando el terreno es enorme | Focus_Avion |
Screen_Nombre_NN | mallas apiladas | pantalla con imágenes en secuencia; un clic pasa a la siguiente | Screen_Menu_01, Screen_Menu_02 |
Display_Nombre | malla 16:9 | monitor que muestra en vivo la pantalla compartida con ?display | Display_Registro |
Character_Nombre | empty o raíz | dónde está una persona con la que se puede hablar; propiedades persona, voice, gender | Character_Alejandra |
Clipboard_Nombre | malla con forma del papel | formulario que el cliente llena; propiedad form = página HTML (o fields) | Clipboard_Inspeccion + form = corte.html |
Show_Nombre | objeto | se ilumina cuando la guía dice su nombre (palabras completas, solo los de la estación actual); propiedad note opcional | Show_Casco, Show_Guantes_De_Nitrilo |
Collider_Nombre | malla simple (caja o plano) | tope invisible para el visitante donde los pasos atravesarían barandales, barandas o cables; nunca se dibuja | Collider_Barandal_Norte |
Button_Nombre | malla o empty con mallas | botón de máquina; reproduce Play_Nombre; propiedad mode = once / toggle / hold / latch | Button_Arranque + Play_Arranque |
Knob_Nombre | malla o empty con mallas | perilla; recorre Play_Nombre de mínimo a máximo; propiedad steps | Knob_Presion + Play_Presion |
Joystick_Nombre | malla o empty con mallas | palanca de dos ejes; mueve Play_Nombre_X y Play_Nombre_Y; propiedades mode (position / rate), sticky, speed, tilt | Joystick_Pluma + Play_Pluma_X, Play_Pluma_Y |
Indicator_Nombre | malla | luz de la máquina que se enciende en el color que diga el archivo de configuración ([indicators.Nombre]) | Indicator_LED1 |
Propiedades personalizadas (Object Properties → Custom Properties) que el visor lee:
| Objeto | Propiedad | Ejemplo |
|---|---|---|
Station_ / Hotspot_ | note — tema de la estación que la guía desarrolla | Aquí se inspecciona cada rollo antes del corte |
Show_ | note — una frase sobre el objeto | Protegen de químicos |
Character_ | persona, voice, gender | Recepcionista, 8 años…, Kore, female |
Clipboard_ | form (página HTML), fields (lista A; B; C...), note | corte.html · Nombre; Fecha; Observaciones... |
Button_ | mode (once, toggle, hold, latch), plays (otra acción) | toggle · Play_Bomba |
Knob_ | steps (posiciones fijas), value (dónde está al cargar la escena, de 0 a 1), plays | 5 · 0.5 |
Joystick_ | mode (position, rate), sticky (no vuelve al centro), speed (acción por segundo a tope), tilt (grados) | rate · 1 · 0.5 · 20 |
Varios objetos en una acción: pistas NLA con el mismo nombre en cada objeto (Play_Arranque en el botón y en el pistón) se exportan como una sola animación. Así se hace que el botón se hunda y la máquina responda, o que la perilla gire y la aguja la siga.
Restricciones de huesos (máquinas): el visor resuelve en vivo, como Blender, estas restricciones de los armatures de la escena: Damped Track; Copy Location y Copy Transforms entre huesos del mismo armature, en espacio mundial; IK de una o dos huesos sin polo (con los bloqueos y límites de IK de sus huesos); Limit Rotation y Limit Location en espacio local. Así, con varias acciones a la vez (la pluma y el brazo), los cilindros siguen apuntando a sus soportes, las mangueras siguen sus puntos de control y la herramienta sigue en su enganche. Las acciones deben mover solo los huesos que de verdad se animan (pluma, brazo, herramienta, giro): lo que siguen las restricciones lo pone el visor. Otras restricciones quedan como las hornea cada acción, y el registro de la conversión las nombra (BLEND_BONE_CONSTRAINTS).
Un tablero en el cuerpo del visitante: un mando que el operador lleva puesto (en el cinturón) se empareja en Blender a un hueso del Avatar (tipo Bone). Viaja con el visitante, se ve en primera persona al bajar la vista, y sus controles se accionan con el puntero, con el rayo del control en VR o con sus teclas. La primera persona mira desde el centro de la parte libre de la pantalla, a la izquierda de la columna de la lista y el diálogo: lo que el operador tiene delante, el mando al bajar la vista, no queda bajo esa columna.
5. Formularios (Clipboard_)
El formulario es una página HTML que escribe el diseñador: cualquier diseño, la hoja de la planta tal cual como tabla, estilos en línea, incluso un script que arme los renglones. Reglas:
- Cada casilla que el cliente llena es un
<input>,<select>o<textarea>conname. - El archivo va en las fuentes de la unidad en Drive: en una carpeta
forms, o junto a los documentos del cliente (from-client/del-cliente). Se encuentra por su nombre (p. ej.corte.html). - En Blender, el plano
Clipboard_Inspeccionlleva la propiedad personalizadaform = corte.html(también valeforms; en el objeto o en los datos de la malla). Modélalo con la forma del papel (horizontal o vertical).
Ejemplo mínimo:
<!doctype html>
<html lang="es"><meta charset="utf-8">
<style>body{font:12px Arial;padding:10px} td,th{border:1px solid #333;padding:2px} input{width:100%;border:0}</style>
<body>
<h2>Inspección · Línea de corte</h2>
<label>O.T. <input name="ot"></label> <label>Fecha <input name="fecha" type="date"></label>
<table>
<tr><th>#</th><th>Longitud</th><th>Defectos</th></tr>
<tr><td>1</td><td><input name="fila1_longitud"></td><td><input name="fila1_defectos"></td></tr>
<tr><td>2</td><td><input name="fila2_longitud"></td><td><input name="fila2_defectos"></td></tr>
</table>
</body></html>
Cómo se usa: en computadora, clic en el portapapeles abre la página en la propuesta; en visor o tableta, un teléfono abre …/FCA/?clipboard y ahí aparecen todos los formularios de la escena. Lo que se escribe aparece en el papel de todos los que están en la escena. Sin página, fields = Nombre; Fecha; Observaciones... genera un formulario sencillo (... = varias líneas). Ejemplos completos: docs/examples/clipboard-forms/ en el repositorio wrk-mgr.
6. Controles de máquina (Button_, Knob_, Joystick_)
- Nombra el control
Button_ArranqueoKnob_Presion(una malla, o un empty con las mallas del control debajo). - Crea la acción
Play_Arranque/Play_Presioncon keyframes del control y de lo que mueve: el botón que se hunde y el pistón que sube; la perilla que gira y la aguja que la sigue. - Exporta.
| Control | Comportamiento | Propiedades |
|---|---|---|
Button_ | reproduce la acción una vez al pulsarlo | mode = toggle: se repite hasta pulsarlo otra vez y vuelve al reposo · mode = hold: avanza mientras se mantiene y regresa al soltar · mode = latch: avanza hasta el final y se queda ahí (encendido) hasta pulsarlo otra vez, que lo regresa (un paro de emergencia que se hunde y se jala) · plays = Play_Otra para usar otra acción |
Knob_ | recorre la acción: inicio = mínimo, fin = máximo; se gira arrastrando, con la rueda, o en VR con el gatillo sostenido subiendo/bajando la mano (o con el stick del control) | steps = 5: posiciones fijas · value = 0.5: dónde está al cargar la escena (un selector de tres posiciones que empieza al centro) · plays |
Joystick_ | dos ejes sobre Play_Nombre_X / Play_Nombre_Y (centro = mitad de la acción); la palanca se inclina sola; vuelve al centro al soltar; se mueve arrastrando o, en VR, con el gatillo sostenido y el stick del control | mode = rate: la acción avanza mientras se empuja y se queda al soltar (grúa, pluma) · speed = 0.5 · sticky = 1 · tilt = 20 |
La acción de una perilla es una pose por valor, sin ciclos. Un hotspot sigue siendo la opción cuando el avatar debe caminar hasta el equipo y hacer un gesto.
Un tablero con varios controles. Un mismo tablero puede llevar varios botones, perillas y palancas a la vez, de cualquier tipo. Cada uno necesita su propio nombre y su propia acción (Button_Arranque + Play_Arranque, Button_Paro + Play_Paro, Joystick_Pluma + Play_Pluma_X / Play_Pluma_Y): dos controles con la misma acción se mueven juntos. Cada control cuenta como un punto de la tarea de su estación, también las copias de Blender (Button_Paro y Button_Paro.001 son dos puntos). En VR cada mano maneja su propio control: la palanca con una y el botón de mantener con la otra.
Lo que hace la máquina con varios controles a la vez (las dos palancas para avanzar, el botón de la palanca con la palanca para el brazo, un selector de modo, un paro de emergencia) se describe en el archivo de configuración, en [conditions] y [functions.Nombre] (capítulo 10.2). En la computadora, cada control puede tener sus teclas (keys) para manejar dos palancas a la vez.
7. La auditoría (/audit-showcase)
Revisa el archivo entregado antes de importarlo. El reporte llega al chat en varios mensajes: resumen y luego hallazgos por severidad.
| Severidad | Hallazgos |
|---|---|
| 🛑 Bloqueante (no importar) | linked_libraries_missing, image_has_no_pixels, images_not_packed, no_entry_points, reserved_loop_prefix, scene_scale_suspect |
| ⚠️ Advertencia (algo falta) | hotspot_without_clip, act_without_hotspot, single_entry_point, skybox_not_emissive, backdrop_not_emissive, sun_not_directional, focus_frames_nothing, screen_frame_unnumbered, screen_frames_misaligned, screen_single_frame, character_without_persona, character_voice_unknown, character_not_rigged, clipboard_without_fields, clipboard_not_a_mesh, clipboard_not_a_plane, collider_not_a_mesh, control_without_clip, control_not_a_mesh, mesh_without_material, names_with_stray_whitespace |
| 💡 Nota | cutout_uses_alpha_blend, opaque_material_carries_alpha, avatar_idle_clip_missing, avatar_walk_clip_missing |
Cada hallazgo trae en el chat qué es y cómo arreglarlo, en el idioma del --es.
8. Especificación completa de la escena
Audiencia: equipo de diseño 3D
Entregable: una escena interactiva por propuesta, mostrada dentro de la propuesta interactiva del cliente
Formato: .blend (Blender 4.x o 5.x hasta 5.2, preferido) o .fbx — entrega el archivo fuente; nosotros nos encargamos de toda la exportación y optimización
Novedades v1.1
- Presupuestos revisados: más triángulos (≤ 600 mil), pero límites nuevos de mallas y materiales — son los que realmente deciden el rendimiento. Ver tabla.
- Avatar encarnable (
Avatar+ clipsIdle/Walk/Act_*): el cliente recorre la escena como un personaje, en tercera o primera persona. - Interacciones (
Hotspot_+Play_+Act_*): puntos donde el cliente acciona equipos — abrir una válvula, pulsar un botón. - Las escenas v1 sin avatar ni hotspots siguen siendo 100 % válidas; las secciones nuevas son opcionales (pero muy recomendadas).
- El soporte del visor para avatar e interacciones está en desarrollo — entrega tus escenas igual desde ya; el pipeline valida los nombres desde la entrega.
Qué vas a construir
La escena aparece dos veces en la propuesta, desde el mismo archivo:
- Maqueta — un modelo a escala de mesa al centro de la galería de la propuesta, como la maqueta de un arquitecto. Es lo primero que ve el cliente.
- Vista interior — al hacer clic en la maqueta, el cliente entra dentro de la escena a escala real: de pie en los puntos que tú definas, sentado en puntos de vista que tú definas (cabina de vehículo, silla de control), o recorriéndola como un personaje (
Avatar) en tercera o primera persona. La presentadora de IA narra mientras el cliente explora.
Diseña para ambas escalas. La escena debe verse atractiva como miniatura desde arriba Y sostenerse a la altura de los ojos desde cada punto de vista que coloques. Detalla lo que una persona de pie va a mirar; no detalles lo que nadie verá de cerca.
Requisitos obligatorios
| Regla | Detalle |
|---|---|
| Unidades | Metros reales. 1 unidad de Blender = 1 m. Una puerta mide ~2.1 m, un barandal ~1.0 m. |
| Transformaciones aplicadas | Todas las escalas aplicadas (Ctrl+A → All Transforms) antes de entregar. |
| Materiales | Solo Principled BSDF. Texturas procedurales horneadas a imágenes, máximo 2048×2048, y máximo ~24 imágenes de textura en total — usa atlas para props repetidos. La memoria de texturas es el recurso más escaso en los dispositivos objetivo. |
| Animación | Acciones con keyframes montadas en pistas NLA. Sin simulaciones físicas, telas ni partículas — hornéalas a keyframes si las necesitas. |
| Presupuesto de geometría | ≤ 600,000 triángulos en total (objetivo ~450 mil). Gasta triángulos donde el cliente va a estar parado; el Avatar (~20–40 mil) cuenta dentro del total. |
| Presupuesto de objetos | ≤ 150 mallas después de unir (une todo lo que comparta material) y ≤ 25 materiales únicos. Este límite decide los FPS más que los triángulos — gasta mallas y materiales como si fueran dinero: una escena de 600 mil triángulos en 120 mallas rinde mejor que una de 250 mil en 600. |
| Autocontenido | Empaca todas las texturas en el archivo (File → External Data → Pack Resources). Sin bibliotecas vinculadas. Archivo empacado ≤ ~150 MB. |
Nosotros comprimimos todo (geometría y texturas) después de la conversión — no necesitas optimizar el tamaño del archivo más allá de estos presupuestos.
Convenciones de nombres — cómo tu escena le habla al visor
El visor lee nombres de objetos y nombres de acciones (animaciones) para saber cómo comportarse. Los objetos que no coinciden con ninguna convención son escenografía normal.
Station_NN_Nombre — puntos de pie (empties)
Un lugar donde una persona puede pararse. Agrega un empty por ubicación, posicionado en el piso (nosotros subimos la cámara a la altura de los ojos automáticamente). La rotación del empty define la dirección inicial de la vista (su eje +Y es "adelante" — activa Display As: Arrows para verlo).
NN= orden del recorrido en dos dígitos (01,02, …). El clic en la maqueta entra por el número más bajo.Nombre= etiqueta legible, CamelCase o con guiones. La presentadora de IA dice este nombre en voz alta — escribeStation_02_SalaDeControl, noStation_02_est2final.- Los visitantes pueden saltar entre estaciones dentro de la escena; colócalas donde el recorrido tenga sentido: entrada → áreas clave → vista final.
- El empty manda. El visor para al visitante exactamente donde lo pusiste, sin corregir nada: por eso tiene que estar apoyado en el piso.
/audit-showcasemide cadaStation_contra el piso real y te avisa si no coincide, antes de importar. - Pon más de uno. Con una sola estación no hay a dónde navegar: no aparecen marcadores de salto y el visitante ve siempre lo mismo.
Seat_Nombre — puntos sentados (empties)
Una vista fija y sentada: cabina, grúa, silla de control. Posiciona el empty en el punto exacto de los ojos de la persona sentada (no en el piso). El visitante puede mirar alrededor desde ahí pero no moverse.
Skybox — el cielo (malla, opcional)
Una esfera o domo invertido grande, material emisivo, textura de cielo equirectangular, rodeando la escena. Se oculta mientras la escena es maqueta; se revela cuando el cliente entra. Si lo omites, el visor pone un cielo simple por defecto — uno real siempre se ve mejor.
La imagen del cielo va conectada a Emission, no a Base Color. El visor hornea el domo en un mapa de entorno dentro de una escena sin luces: un domo con la textura en Base Color sale negro y toda la escena queda a oscuras (así se entregó AER). /audit-showcase lo reporta como skybox_not_emissive.
Loop_Nombre — animación ambiental (nombres de acciones)
Toda acción cuyo nombre empiece con Loop_ se reproduce automáticamente, por siempre, cuando el cliente está dentro: Loop_Antorcha, Loop_Transportador, Loop_Trafico. Haz que el primer y último keyframe coincidan para que el ciclo sea continuo.
Demo_Nombre — la demostración de la portada (nombres de acciones, opcional)
La portada de una capacitación (la pantalla del módulo del player) muestra toda el área de entrenamiento en miniatura: cada estación, asiento y hotspot con el sujeto. Las paredes y el techo se cortan 2,2 m por encima del piso más alto donde se para el alumno. Lo que se mueve ahí lo decides tú:
- Con acciones
Demo_. Toda acción cuyo nombre empiece conDemo_se reproduce ahí, todas juntas, más lasLoop_. - Empiezan en el mismo instante y vuelven a empezar cuando termina la más larga; una más corta se queda en su último cuadro hasta entonces.
- El nombre después de
Demo_es libre, y puede repetirse con el sufijo de Blender (Demo_Controles.001). - Si alguna mueve al avatar, aparece donde lo dejaste en el archivo; si ninguna lo mueve, no se ve.
- Sin acciones
Demo_. El avatar recorre el ejercicio, ronda tras ronda, mientras lasLoop_siguen corriendo. - Camina de estación en estación, en su orden. En cada una va a sus hotspots y hace su gesto (
Act_) mientras el equipo se mueve (Play_). - Varias estaciones seguidas en un mismo lugar son una sola parada.
- Camina por el
Navmeshsi lo hay; si no, en línea recta, como en un ejercicio. - Al terminar la ronda vuelve a la primera estación y empieza otra.
- Nada de esto pasa dentro de un ejercicio. Al entrar, todo vuelve a su pose inicial, y las acciones
Demo_nunca se reproducen ahí.
En ALF la demostración de demolición es Demo_: el operador con el control remoto (Demo_Operador, Demo_Controles), el Brokk golpeando la pared (Demo_Brokk_v3) y los 50 pedazos de la pared cayendo (Demo_Pared_Trozo_033_0…). TAC no tiene Demo_: su portada muestra al avatar recorriendo sus cinco estaciones, usando el micrómetro y escribiendo.
Avatar — el personaje del cliente (armature, opcional)
Un personaje que el cliente "encarna" al entrar: puede verlo en tercera persona (cámara al hombro), mirar por sus ojos en primera persona, o soltarlo y volar libre (modo dron, el comportamiento actual). Si la escena no trae Avatar, el visor funciona como hasta ahora — solo modo dron.
- El armature raíz se llama
Avatary todas sus mallas cuelgan de él. Su posición en el archivo da igual — el visor lo coloca en la estación de entrada —, y también dónde queden sus huesos respecto a su origen: el visor lo centra en sus pies (la raíz del esqueleto). - Clips del avatar (en NLA como todo lo demás):
Idle(opcional) — parado, en bucle.Walk(opcional) — caminar en el sitio (sin desplazamiento de la raíz), a cadencia natural de ~1.4 m/s; el visor sincroniza la velocidad de reproducción con el movimiento real para que los pies no patinen.- Si el
Avatarno traeIdleoWalk, el visor usa unos compartidos (una postura y un caminar de hombre, en el esqueleto de Character Creator). Los que traiga la escena siempre tienen prioridad: inclúyelos cuando la escena necesite unos propios, por ejemplo para un avatar de mujer. Act_Nombre(opcionales) — acciones de una sola vez para las interacciones (ver hotspots). UnAct_Operategenérico sirve de comodín para cualquier hotspot sin clip específico.Avatar_Eyes(empty, opcional) — el punto exacto de los ojos; define la cámara en primera persona *y la altura de ojos en cadaStation_**. Emparentarlo al hueso de la cabeza es lo recomendado, pero también lo leemos si queda suelto en la escena. Si falta, usamos ~94 % de la altura medida del avatar.- Las mallas que deben desaparecer en primera persona (cara, pelo, pestañas, gafas) se nombran con el prefijo
Head_(Head_Face,Head_Hair). Sin mallasHead_, el visor oculta el avatar completo en primera persona. - Se oculta a escala maqueta, igual que el
Skybox. Sus triángulos cuentan en el presupuesto (~20–40 mil es lo típico).
Hotspot_Nombre — interacciones (empties) — el trío de nombres
Un punto donde el cliente hace algo: abrir una válvula, pulsar un botón, revisar un panel. Una interacción se define por hasta tres piezas que comparten exactamente el mismo nombre:
| Pieza | Tipo | Papel |
|---|---|---|
Hotspot_AbrirValvula | empty en la escena | El ancla (obligatoria): posición y orientación exactas donde una persona se pararía a hacerlo, con +Y hacia el equipo. |
Play_AbrirValvula | acción de la escena | El lado del equipo: el volante gira, el panel se enciende. Se reproduce una vez al activarse y se queda en su último fotograma (la válvula abierta sigue abierta; un accesorio que la acción esconde al final sigue escondido). Lo que se ve antes de activarla es la pose base del objeto: un accesorio que solo debe existir durante la acción lleva escala 0 como base. |
Act_AbrirValvula | clip del avatar | El lado humano: el gesto de alcanzar y girar. |
Comportamiento del visor: al acercarse (~2.5 m) aparece el aviso; al activar, el avatar se desliza al ancla y Act_ + Play_ se reproducen a la vez; después vuelve a Idle. Mientras dura la acción, un recuadro muestra de cerca lo que anima Play_ (el instrumento, la válvula): modela la lectura legible y deja la animación en el valor que debe leerse. reading en la tabla [Hotspot_Nombre] del archivo de configuración (o una propiedad note en Blender) hace que la guía diga la lectura al terminar. Por eso el ancla importa: colócala exactamente donde deberían estar los pies y la mano llegará al equipo. Sin avatar (o en modo dron), hacer clic en el marcador reproduce solo Play_ — los hotspots funcionan en toda escena, con o sin avatar.
- Clips de interacción: ≤ ~10 segundos.
- El nombre se muestra en pantalla y la presentadora lo pronuncia —
Hotspot_AbrirValvula, noHotspot_hs01.
Focus_Nombre — el sujeto de la maqueta (objeto o empty, opcional)
Dile al visor qué es lo que la maqueta muestra. En la galería la escena se ve como maqueta: el visor la escala para que su extensión más grande mida unos 4 m. Si la escena necesita mucho más entorno que sujeto — la cabina de FER tiene ventanas al frente y atrás, así que las vías y el piso deben correr lejos en ambos sentidos — el entorno se queda con esa escala y el sujeto termina diminuto.
- Nombra el objeto principal
Focus_Nombre(Focus_Tren). Si el sujeto son varios objetos, emparéntalos bajo un empty con ese nombre: cuenta todo lo que cuelga de él. VariosFocus_*enmarcan su unión. - La maqueta se escala y se centra en el
Focus_, no en la escena completa. El resto del entorno conserva su tamaño real y, solo en la maqueta, se recorta a una base redonda un poco más ancha que el sujeto, como una maqueta de tren sobre su peana. - Dentro de la escena no se recorta nada: las vías y el piso están completos, a escala real, hasta donde los hayas modelado.
- Un
Focus_sin mallas debajo no enmarca nada y el visor vuelve a medir la escena completa;/audit-showcaselo reporta comofocus_frames_nothing. - Sin ningún
Focus_todo funciona como siempre: manda la extensión más grande de la escena.
Icon_Camera — la vista del icono del módulo (cámara, opcional)
/gen-player renderiza el icono del módulo en el LMS desde este archivo: una imagen cuadrada de 1080 px, como los iconos de los demás módulos. Sin cámara, encuadra el sujeto de la maqueta (Focus_, o toda la escena) desde detrás y por encima de la primera estación, y deja fuera lo que se interponga entre la cámara y el sujeto (un barandal, los paneles de una cabina). Para elegir la vista tú, pon una cámara llamada Icon_Camera: se usa tal cual. El avatar, el Skybox (el cielo es neutro, como en la maqueta), los Collider_ y la Navmesh nunca salen en el icono. La luz es la del visor: el Sun del archivo y un cielo neutro que nada tapa salvo el sujeto, así que un sujeto dentro de una cabina queda iluminado.
Screen_Nombre_NN — pantallas con imágenes en secuencia (mallas)
Un monitor, tablet o kiosco que muestra una serie de imágenes (las pantallas de un sistema de registro, por ejemplo). Modela la pantalla como un plano con la primera imagen y duplícalo en el mismo sitio una vez por imagen: Screen_Registro_01, Screen_Registro_02, … cada copia con su propia imagen en el material (conectada a Emission, para que se vea encendida con cualquier luz). El visor muestra solo la _01; un clic, un toque o el gatillo de VR sobre la pantalla pasa a la siguiente y, tras la última, vuelve a la primera.
- Los cuadros deben coincidir exactamente en posición y tamaño (Shift+D sin mover);
/audit-showcaseavisa si alguno quedó desplazado. - Numera desde
_01sin huecos. Un cuadro sin número (Screen_Menu) es escenografía normal; una pantalla con un solo cuadro no hace nada al hacer clic. - Cada imagen cuenta en el presupuesto de texturas; exporta las capturas a 2K o menos.
- La guía de voz sabe qué pantalla está viendo el cliente y en qué imagen va; con una tabla
[Screen_Nombre]connoteen el archivo de configuración de la escena, la comenta.
Display_Nombre — pantalla en vivo (malla)
Un monitor que muestra, en vivo, la pantalla de una computadora: el programa real del cliente (su sistema de registro, por ejemplo) corriendo mientras el cliente practica frente al personaje. Modela el monitor como un plano de 16:9 con UV completo (la imagen ocupa todo el plano) y nómbralo Display_Registro. El material que le pongas es lo que se ve cuando nadie está compartiendo.
- La computadora que comparte abre la propuesta con
?displayal final de la dirección y pulsa Compartir esta pantalla; a partir de ahí todos losDisplay_*de la escena muestran esa pantalla. Ambos equipos deben estar en la misma red. - Un solo plano por pantalla; varios
Display_*muestran la misma imagen. - Para una secuencia fija de imágenes usa
Screen_;Display_es para software en vivo.
Character_Nombre — personas con las que se puede hablar (empty o raíz)
Una persona de la escena con la que el cliente practica una conversación real por voz: un huésped en la recepción, un cliente en la ventanilla. El personaje no se modela en la escena: el equipo de operaciones lo entrega en el comando de publicación, como el showcase:
/gen-proposal UNIDAD --publish --showcase <escena> --character <modelo> --persona <doc> --idle <clip> --talk <clip>
--character: export de Character Creator 4 del personaje (.fbx, T-pose, sin animación): el mismo estándar que el presentador.--persona: Google Doc con líneasNombre:,Persona:(quién es y qué quiere),Líneas:(opcional: lo que dice y los datos que da — teléfono, correo, domicilio — una por renglón; la persona los usa tal cual, nunca inventa otros) yVoz:(Puck,Charon,Fenrir,Orusmasculinas;Aoede,Leda,Zephyr,Korefemeninas) oGénero:.Persona:yLíneas:abarcan los renglones que siguen; nombre, voz y género ocupan uno solo. Cada personaje habla con una voz distinta de la guía.--idle/--talk: clips .fbx de solo movimiento sobre el esqueleto de Character Creator (exportados de Character Creator o iClone, o comprados en ActorCore): de pie en bucle, y mientras habla. Un clip de Mixamo se reorienta al esqueleto CC al publicar. Sin estos flags se usan los últimos clips importados.
Tu parte en la escena es el lugar: un empty (o cualquier objeto) llamado Character_Nombre donde va la persona, con el mismo Nombre que el documento de persona, mirando hacia donde está el cliente. El visor pone ahí el modelo entregado y oculta el marcador. Al acercarse (~2,5 m) aparece el aviso E — 💬 Nombre; con E, un clic o el gatillo de VR empieza la conversación y la guía calla; termina con E, otro clic, alejándose (> 4 m) o cuando la persona se despide, y la guía comenta cómo fue.
- Sin escena (
--charactersin--showcase), la persona aparece a tamaño real en la sala del cliente con el botón Practicar en tu sala (RA), con una pantallaDisplay_generada delante. - Con escena, en un visor con passthrough ese mismo botón coloca a la persona y las pantallas
Display_*en la sala del cliente; la escena se gira para que la persona mire haciaStation_01. - Recorridos (opcional): en lugar de quedarse en su lugar, la persona puede seguir un recorrido entre estaciones — saludar, caminar al archivo por la
Navmesh, sentarse al escritorio, trabajar un rato, levantarse y repetir; conversar lo pausa. Se escribe en el archivo de configuración (pathde[Character_Nombre], ver el capítulo 10 del sistema de propuestas). Una estación que solo usan los personajes es unStation_NN_Nombremás, que ningún ejercicio lista en sutask_stations; si se sienta, el empty de esa estación mira hacia donde mira la persona sentada. Sus acciones son animacionesAct_Nombrede la escena (las mismas delAvatar) o importadas aparte.
Clipboard_Nombre — formularios que el cliente llena (malla, opcional)
Un portapapeles con un formulario que el cliente llena durante la práctica: el alta de un cliente, un reporte de incidente, la hoja de inspección de la planta. Modela el portapapeles como un plano con UV completo, con la forma del papel (vertical u horizontal), y nómbralo Clipboard_Registro. El material que le pongas es lo que se ve cuando nadie está en la escena; adentro, el visor dibuja el formulario con lo que se va escribiendo.
- El formulario es una página HTML que tú escribes: cualquier diseño, la hoja de la planta tal cual como tabla, estilos en línea, incluso un script que arme los renglones. Cada casilla que el cliente llena es un
input,selectotextareaconname. Guarda la página en las fuentes de la unidad en Drive (en una carpeta llamadaforms, o junto a los documentos del cliente) y pon su nombre en la propiedad personalizadaformdel objeto (corte.html; también valeforms, y la propiedad puede estar en el objeto o en los datos de la malla). También sirve una dirección completa, o la página misma dentro de la propiedad. Ejemplos listos endocs/examples/clipboard-forms/. - Sin página: una lista de campos en la propiedad
fields, separados por;(Nombre; Fecha; Observaciones...; un campo que termina en...es de varias líneas) genera un formulario sencillo. Opcional:notecon una frase sobre para qué sirve el formulario. - Cómo se llena: en una computadora, un clic en el portapapeles abre la página en la misma propuesta; en visor o tableta, se abre la propuesta en el teléfono con
?clipboardal final de la dirección y ahí aparecen todas las páginas de la escena. Lo que se escribe aparece en el papel de todos los que están en la escena (una foto de la página; hojas de estilo e imágenes externas no salen en la foto, por eso estilos en línea). - La guía de voz solo se entera de un formulario cuando es parte de una tarea (ver Las estaciones son las tareas): al enviarlo o al cerrarlo con todos los campos llenos.
/audit-showcasereporta unClipboard_sinformnifields, que no es una malla, o que no es un plano (clipboard_not_a_plane): un portapapeles modelado o una computadora entera con ese nombre no se pinta — el papel o la pantalla necesitan su propio plano. - Dentro del recorrido, al tocar el portapapeles la cámara se acerca al objeto y la página aparece sola sobre él, sin marco; al cerrarla la cámara vuelve.
Show_Nombre — objetos que la guía señala uno por uno (objetos, opcional)
Para una estación con varios objetos que la guía explica de uno en uno — el EPP sobre una mesa, las herramientas de un banco —, nombra cada objeto Show_Nombre (Show_Casco, Show_Guantes_De_Nitrilo). Mientras la guía habla de un objeto, ese objeto brilla en naranja; al pasar al siguiente, el anterior se apaga.
- Cada
Show_pertenece a la estación (Station_oSeat_) más cercana: basta con nombrar los objetos de la mesa, no hay que emparentarlos con nada. - El nombre es lo que la guía dice en voz alta; escríbelo como se pronuncia, con guiones bajos entre palabras.
- Opcional: una propiedad personalizada
noteen el objeto con una frase sobre él (Protegen de químicos); la guía la desarrolla al describirlo. - Si el objeto tiene varias piezas, emparéntalas bajo un empty con el nombre
Show_: brilla todo lo que cuelga de él. - El orden lo decide la guía al hablar; el brillo dura mientras lo describe y se apaga solo si nadie lo cambia en unos segundos.
- Un clic sobre el objeto lo ilumina y la guía lo describe (otra vez si hace falta), con su
notesi la tiene. - El objeto se ilumina cuando la guía dice su nombre: por eso el nombre debe ser lo que se dice del objeto (
Show_Guantes_De_Nitrilo, noShow_Obj17). - El nombre se reconoce por palabras completas, en orden:
Show_Tizase ilumina con «la tiza» o «las tizas», no con «garantiza». Las palabras cortas (de, la, y) pueden sobrar o faltar («guantes carnaza» vale porShow_Guantes_De_Carnaza); un número se dice tal como está escrito en el nombre («20 metros» paraShow_Cinta_Métrica_20_metros, así que escríbelo como lo dirá la guía). Si un nombre está contenido en otro (Show_GuantesyShow_Guantes_De_Carnaza), gana el más largo cuando se dicen todas sus palabras. - Solo pueden iluminarse los objetos de la estación en la que está el cliente: un objeto del siguiente banco con una palabra en común no roba el brillo.
Navmesh — la superficie por donde se camina (malla, opcional)
Cuando el visitante va a una estación o a un punto interactivo con un clic, el personaje recorre un camino sobre la Navmesh de la escena: rodea mesas, barandales y rodillos en vez de atravesarlos.
Pon una malla llamada Navmesh (o Navmesh_Planta, cualquier nombre que empiece así) con la superficie caminable: pasillos, plataformas, rampas. El visor la oculta al cargar (no se dibuja, no proyecta sombra, no sirve de tope) y construye con ella una cuadrícula del piso. Solo los Collider_ bloquean celdas encima de ella: el resto de la escenografía no cuenta, así que pon un Collider_ en todo lo que el visitante deba rodear. Entre celdas nunca se sube ni se baja más de un escalón.
- Puede ser una sola malla o varias; basta con que estén a ras del piso real (± un escalón).
- Sin
Navmesh, un clic lleva en línea recta. - Ajustes en el panel y en el archivo de configuración, grupo
nav: tamaño de celda, altura de escalón, ancho del visitante, velocidad del recorrido.
Collider_Nombre — topes invisibles para el visitante (mallas, opcional)
El visitante choca con las mallas de la escena (seis rayos horizontales, del tobillo a la cabeza). Donde la geometría deja huecos entre esos rayos — las barras de un barandal, una baranda, un cable, una vitrina muy fina — pon una caja o un plano sencillo con el nombre Collider_Nombre (Collider_Barandal_Norte) cubriendo la zona por donde no debe pasar. El visor lo oculta al cargar: nunca se dibuja, no proyecta sombra, no sirve de suelo ni se puede señalar; solo lo sienten los pasos del visitante.
- Déjalo visible en Blender con cualquier material; el visor lo esconde.
- Una caja por tramo basta; no hace falta ajustarla a la forma del objeto.
/audit-showcasereporta unCollider_que no sea una malla (collider_not_a_mesh).
Door_Nombre y Open_Nombre — puertas que se abren y se cruzan (malla o raíz, y una acción, opcional; v1.6)
Una puerta es el objeto Door_Nombre (Door_Almacen): la hoja como malla, o una raíz con la hoja debajo. Su acción de la escena Open_Nombre (Open_Almacen) la abre: el visor la reproduce hacia adelante al abrir y hacia atrás al cerrar, y se queda en su último fotograma.
- Un clic en la puerta la abre; otro la cierra. Cerrada, el visitante choca con ella y las rutas (clic en un marcador) no pasan por su vano; abierta, se cruza caminando.
- La
Navmeshdebe pasar por el vano: la puerta cerrada lo cierra sola. - Una puerta sin acción
Open_no se abre: se queda como pared (el visor lo avisa en la consola). - A otro ejercicio (PROP-60): con la propiedad personalizada
exerciseen la puerta (el código del ejercicio del mismo módulo, o su sufijo:PR), la puerta está cerrada con llave hasta que el alumno completa el ejercicio actual; entonces se abre y, al cruzarla, empieza ese ejercicio (con su tarjeta de inicio dentro de la escena). Mientras está cerrada con llave, un clic avisa qué falta.
Button_Nombre, Knob_Nombre y Joystick_Nombre — controles de una máquina (mallas, opcional)
Botones, perillas, palancas e indicadores que el cliente acciona directamente sobre el equipo: pulsa el botón de arranque y el transportador se mueve; gira la perilla de presión y la aguja del manómetro la sigue. No necesitan ancla ni avatar: se accionan donde esté el cliente, con un clic, con el gatillo del visor o con la mano.
- Nombra el control
Button_ArranqueoKnob_Presion(una malla, o un empty con las mallas del control debajo). Lo que hace está en la acciónPlay_Arranque/Play_Presion: ahí va, en keyframes, tanto el movimiento del control como el de lo que mueve — el botón que se hunde y el pistón que sube; la perilla que gira y la aguja que la sigue. Varios objetos en una acción: pistas NLA con el mismo nombre, igual que enPlay_de un hotspot. Para usar otra acción, pon su nombre en la propiedad personalizadaplays. Button_reproduce la acción una vez al pulsarlo. Con la propiedadmode:toggle(la acción se repite hasta pulsarlo otra vez; al apagarlo todo vuelve al reposo),hold(avanza mientras se mantiene pulsado y regresa al soltarlo) olatch(avanza hasta el final y se queda ahí hasta pulsarlo otra vez, que lo regresa: un paro de emergencia que se hunde y se jala; su acción termina con el botón adentro).Knob_recorre la acción: el principio es la perilla al mínimo, el final al máximo. Se gira arrastrando con el ratón (o con la rueda), o en el visor sujetando el gatillo y subiendo o bajando la mano. La propiedadsteps(5) la hace de posiciones fijas, yvalue(de 0 a 1) dice dónde está al cargar la escena:steps = 2yvalue = 0.5es un selector de tres posiciones que empieza al centro.Indicator_es una luz de la máquina (una malla): se enciende en el color que diga el archivo de configuración ([indicators.Nombre]), según el estado de la máquina; apagada, se ve con su propio material. Si es una pantalla que muestra texto ([indicators.Nombre.text]), dale UV completa: la imagen llena la pantalla, con la parte de arriba de la pantalla arriba y su izquierda a la izquierda, como la ve quien la usa (una UV volteada muestra las letras al revés).- La acción de un
Knob_debe ser una pose por valor, sin ciclos: a cada punto de la acción le corresponde una posición de la perilla y de lo que indica. Joystick_tiene dos ejes y mueve dos acciones:Play_Nombre_X(izquierda → derecha) yPlay_Nombre_Y(atrás → adelante); el centro de cada acción es la palanca al centro. Modela la palanca con el pivote en su base: el visor la inclina solo (propiedadtilt, grados; 20 por defecto). Por defecto cada eje recorre su acción como una perilla (mode = position); conmode = ratela acción avanza mientras la palanca está empujada y se queda donde está al soltar — la pluma de una grúa que sigue girando mientras se sostiene (propiedadspeed: fracción de la acción por segundo a tope, 0.5 por defecto). Al soltar, la palanca vuelve al centro, salvo consticky = 1. Se mueve arrastrando con el ratón, o en el visor sujetando el gatillo sobre ella y usando el stick del control; ese stick también gira una perilla sujeta.- Varios controles en un tablero. Un tablero puede llevar varios
Button_,Knob_yJoystick_juntos. Cada control lleva su propio nombre y su propia acción: dos controles con la misma acción se mueven juntos. Cada uno es un punto de la tarea de su estación, también una copia de Blender (Button_ParoyButton_Paro.001son dos puntos con la misma etiqueta). Se acciona el control bajo el puntero (o bajo el rayo del control en VR), nunca el vecino; en VR cada mano sujeta su propio control. Lo que hace la máquina con varios controles a la vez (las dos palancas, un botón con la palanca, un selector) no va en Blender: va en el archivo de configuración ([functions.Nombre]), que nombra la acciónPlay_de la máquina. Por eso la acción de cada control mueve solo el control y la mano del operador. Una acción de la máquina que mueve una palanca lleva la máquina en reposo a la mitad, igual que las acciones de la palanca; las demás, al inicio (o donde digarest). Las acciones de varias funciones se suman, así que pueden compartir huesos, como las mangueras que siguen a la pluma y al brazo. Para que la máquina se desplace libremente (las orugas), su acción mueve solo la raíz del rig y la función llevatravel = true: la máquina va tan lejos como se la conduzca. Pon unCollider_alrededor de la máquina: viaja con ella, la detiene contra paredes y personas, y el visitante choca con ella donde esté. Un cable entre dos partes (de la máquina a su fuente de alimentación) es un emptyCable_Nombrecon las propiedadesfromyto(los nombres de las dos partes que une),radius(en metros, 0.012 por defecto) ycolor: el visor lo dibuja desde cada extremo hasta el suelo y por el suelo, y lo vuelve a dibujar si un extremo se mueve (la máquina se desplaza, el enchufe se saca). - Restricciones de huesos. El visor resuelve en vivo las restricciones de un armature de máquina como Blender: Damped Track, Copy Location y Copy Transforms (entre huesos del mismo armature, espacio mundial), IK de una o dos huesos sin polo, Limit Rotation y Limit Location (espacio local). Los cilindros, las mangueras y la herramienta quedan en su lugar con varias acciones a la vez. Anima solo los huesos que se mueven de verdad; lo demás lo ponen las restricciones.
- Un mando en el cuerpo del visitante. Empareja el mando (sus
Button_,Knob_,Joystick_eIndicator_) a un hueso delAvatar: viaja con el visitante y se acciona igual. La carcasa puede ir con skin a ese mismo hueso. En tercera persona el visor muestra un primer plano del mando en una esquina, visto desde los ojos del operador; lo que encuadra es el padre común de los controles más las mallas con skin solo a él. En primera persona, al mirar hacia abajo, la vista se coloca sobre el mando para que quepa entero. Los nombres cortos de los controles (labelen el archivo de configuración) flotan a su lado, en ese primer plano y en primera persona. - Dos botones en una palanca. Cada botón es su propio
Button_con su propia acción, hijo de la palanca para que se incline con ella (en el Brokk,Button_Percutores B1.LL yButton_B1LRes B1.LR, lado a lado en la cabeza de la palanca izquierda). /audit-showcasereporta un control sin su acciónPlay_o que no es una malla.
Luces
Tu Skybox es la luz principal de la escena. El visor lo convierte en un mapa de entorno (IBL): de ahí sale toda la luz ambiental y todos los reflejos del metal. Es lo mismo que hace el "world" de Blender, y es la palanca más grande que tienes sobre cómo se ve la escena. Un cielo bien expuesto ilumina bien; un cielo plano u oscuro deja todo apagado.
El Sun decide hacia dónde caen las sombras. El visor toma su dirección y su color, no su intensidad: Blender exporta W/m² convertidos a lux y el visor los vuelve a reescalar, así que la intensidad no sobrevive el viaje de forma útil. El visor pone su propia intensidad, calibrada con la exposición. Orienta el Sun como quieras que caigan las sombras y no te preocupes por su "Strength".
Se usa el primer Sun (luz direccional) de la escena; un segundo sol no se enciende. Las lámparas point y spot sí: en el player, dentro de la escena a escala real, todas las que pongas iluminan con la intensidad que les diste (en la maqueta van apagadas, porque de tan cerca la quemarían). Para un interior son la luz que cuenta: ilumínalo como quieras que se vea.
Tiene que ser una lámpara de tipo Sun: una luz Point o Area llamada "Sun" no cuenta (AER entregó un point de 17,8 millones de candelas y el visor lo ignoró: sin dirección de sol, sin sombras autoradas). /audit-showcase lo reporta como sun_not_directional.
El piso no fija la escala de la maqueta. En la galería la escena se muestra como maqueta: el visor escala la extensión más grande de la escena (sin contar Skybox y Avatar) a 4 m. Un piso o explanada mucho más grande que el sujeto se convierte en la maqueta entera y el sujeto queda diminuto (el avión de AER medía 0,8 m sobre una explanada de 185 m). Recorta el piso a la zona caminable, o — si la escena necesita ese entorno, como unas vías que deben verse largas desde la cabina — nombra el sujeto Focus_Nombre y el piso deja de contar. /audit-showcase lo reporta como diorama_fit_dominated.
Hasta 2026-08-14 esta sección decía que todas las luces iluminaban la vista interior. No era cierto: el conversor nunca las exportaba. Ya se corrigió.
Las estaciones son las tareas (sin nada nuevo que nombrar)
La visita no es un paseo: es un ejercicio por tareas, y las tareas son tus Station_NN_Nombre (y después los Seat_) en su orden. No hay que agregar nada:
- La instrucción de cada tarea es
tasken la tabla[Station_NN_Nombre]del archivo de configuración de la escena (ver la guía del sistema, capítulo 10); sin ella, la propiedadnotede la estación en Blender; sin nada, su nombre. - Lo que hay que hacer ahí son los objetos interactivos más cercanos a esa estación — igual que los
Show_: elHotspot_, elClipboard_, elCharacter_, laScreen_o los controles que estén junto a ella. - La tarea se da por hecha cuando el visitante llega a la estación y hace todo lo que hay ahí: acciona el hotspot, hace clic en cada objeto
Show_, entrega la hoja o la cierra contestada (si la página marca camposrequired, todos ellos; si no, basta con haber cambiado algo; la hoja generada porfieldspide todos sus campos y tiene botón Entregar; cerrarla sin tocar le gana un recordatorio de la guía; unClipboard_sinformnifieldsno cuenta), termina la conversación, pasa la pantalla hasta su última imagen, acciona el control. Una estación sin nada que hacer se cumple al llegar. - Varias tareas en un mismo lugar. Cuando varias tareas se hacen donde el visitante ya está (en el Brokk: encenderlo, sus orugas, su brazo y su martillo, todo desde el sitio del operador), pon sus
Station_NN_Nombreen el mismo punto (a menos de 25 cm uno de otro). El visitante no camina entre ellas: al terminar una tarea, la siguiente de ese lugar empieza ahí mismo, con su lección y sus preguntas. Se ve un solo marcador por lugar, el de la tarea que toca. Las funciones y los estados de la máquina eligen su tarea constationen el archivo de configuración.
La guía pide una tarea a la vez, al llegar explica la estación y dice qué hacer ahí, confirma cada tarea cumplida, da una pista si el visitante se atasca y cierra el ejercicio con una retroalimentación breve. En pantalla aparece la lista con las tareas hechas tachadas; se pueden hacer en cualquier orden.
Después de cada tarea la guía hace dos preguntas sobre la estación (solo de lo que enseñó al llegar; la lección sale del archivo de configuración de la escena y del material) y califica las respuestas. Al final, el examen: todo el ejercicio otra vez, solo, en orden, sin marcadores ni lista; la guía calla hasta el cierre. Nada de esto se nombra en Blender.
Cómo usa el visor tu escena
- La cámara entra a la altura de ojos del avatar entregado, sobre el empty
Station_tal como lo colocaste (sin raycast, sin correcciones):Avatar_Eyesmenos la base del avatar. SinAvatar_Eyesusamos ~94 % de su altura medida; sin avatar, 1.7 m. LosSeat_se respetan exactos. - El cliente puede mirar (arrastrar), girar y caminar (flechas — se sigue el terreno: banquetas y escaleras funcionan, subidas mayores a ~3.5 m no), alternar una vista aérea (barra espaciadora) y saltar entre estaciones (marcadores numerados).
- Con
Avatar, el cliente entra en tercera persona y puede alternar tercera persona / primera persona / modo dron. El avatar respeta las mismas reglas de suelo que la cámara. - En VR, el visitante ve su propio cuerpo del cuello hacia abajo: el cuerpo sigue al visor (caminar físico incluido), gira cuando el visitante gira — no cuando solo mira — y alterna Idle/Walk según la velocidad real.
- Manos rastreadas (IK): con las manos libres (sin controles), las manos y dedos REALES del visitante mueven los brazos y dedos del avatar. Para que funcione, el rig debe conservar: (1) los nombres de huesos
CC_Base_*exactos de Character Creator — sin renombrar ni re-targetear al exportar; (2) el clipT_Poseen el export; (3) escala en metros, animaciones in-place; (4) un solo armature bajoAvatar. Si el visitante baja las manos (fuera de las cámaras del visor), los brazos vuelven suavemente a la animación — es el comportamiento esperado, no un error. - Cerca de un
Hotspot_*aparece el aviso de interacción; el visor desliza el avatar al ancla antes de reproducir los clips. - Un clic (o el gatillo de VR) sobre una pantalla
Screen_pasa a la siguiente imagen; cerca de unCharacter_, E (o un clic) abre una conversación por voz con ese personaje, que habla con su propia voz. - Consecuencia de diseño: el suelo entre estaciones debe ser transitable y continuo; compón cada estación como una toma, pero recuerda que el cliente puede caminar fuera de ella.
- Próximamente: las mismas escenas se explorarán también con visores de realidad virtual (Quest). No requiere trabajo extra de tu parte — pero la escala real en metros y los presupuestos de rendimiento importan aún más.
Entrega y retroalimentación
Entrega el archivo igual que cualquier modelo de showcase (enlace de Drive al equipo de operaciones). El pipeline de publicación valida la escena automáticamente y reporta los problemas por nombre en la tarjeta de chat — p. ej. "Station_03 está 4.2 m sobre el piso — las estaciones van en el piso" o "la escena mide 17 m de ancho pero declara estaciones caminables — reescala a metros." Corrige y vuelve a entregar; republicar es barato y el modelo solo se reconvierte cuando el archivo realmente cambia.
Antes de importar nada, el equipo de operaciones puede pedir una revisión del archivo con /audit-showcase <enlace de Drive>: abre tu archivo sin convertirlo ni publicarlo y responde en el chat con lo que encontró — bibliotecas vinculadas que faltan, imágenes que Blender no pudo cargar, objetos ocultos que no llegarían a exportarse, nombres de clips fuera de convención, los presupuestos de la escena, y desde septiembre de 2026 también si el Sun es direccional, si el Skybox es emisivo y qué objeto fija la escala de la maqueta. Si algo no cuadra, lo sabrás en minutos y sin tocar la propuesta del cliente. La tarjeta muestra los primeros seis elementos afectados de cada hallazgo; el informe completo (todas las texturas con su tamaño y los materiales que las usan, objetos ocultos, estaciones contra su piso) está en el enlace al final de la tarjeta.
Dos casos se rechazan de inmediato, porque el cliente vería una escena vacía: un archivo sin geometría (lo que produce un archivo maestro cuyas bibliotecas vinculadas no se entregaron con él) y una textura sin píxeles (una imagen cuyo archivo Blender no pudo cargar). El mensaje nombra los objetos que sí llegaron, o los materiales afectados.
Lista de verificación antes de entregar
- 1 unidad = 1 metro; escalas aplicadas; la escena tiene tamaño real
- Al menos un empty
Station_(oSeat_), en el piso (asientos: a la altura de los ojos), dirección "adelante" verificada - Los nombres de estación y hotspot son presentables — la presentadora de IA los pronuncia
- Domo
Skyboxpresente (u omitido a propósito), con la imagen conectada a Emission - Una lámpara de tipo Sun (no point/area) orientada como quieras las sombras
- El piso o explanada no supera ~1,5× el tamaño del sujeto, o el sujeto se llama
Focus_Nombre— si no, el piso fija la escala de la maqueta - Movimiento ambiental montado como acciones NLA
Loop_*, con ciclo continuo - Opcional: la demostración de la portada montada como acciones
Demo_*; sin ellas, el avatar recorre las estaciones y sus hotspots - Si incluyes
Avatar: mallas de cabeza con prefijoHead_;Avatar_Eyesen el hueso de la cabeza (recomendado);IdleyWalken NLA solo si la escena necesita unos propios (Walken el sitio, sin desplazamiento de raíz) - Hotspots: ancla donde van los pies, +Y hacia el equipo; el trío
Hotspot_X/Play_X/Act_Xcomparte el nombre exacto - Pantallas:
Screen_X_01,_02… duplicadas en el mismo sitio, una imagen por cuadro (Emission), numeradas sin huecos - Pantalla en vivo:
Display_X, plano 16:9 con UV completo - Personajes con los que se habla: un empty
Character_Xdonde va la persona (el modelo, la persona y los clips llegan con--character,--persona,--idle,--talk) - Objetos que se describen uno por uno en una estación: cada uno nombrado
Show_Nombre, connoteopcional - Formularios que el cliente llena: planos
Clipboard_Nombrecon la página HTML enform(o una lista enfields) - Topes invisibles donde los pasos atravesarían barandales o cables: cajas
Collider_Nombre - Controles de máquina:
Button_X/Knob_Xcon su acciónPlay_X(el control y lo que mueve, en una sola acción);Joystick_XconPlay_X_X/Play_X_Y - Principled BSDF en todo; texturas procedurales horneadas; texturas ≤ 2K, ≤ ~24 imágenes, empacadas en el archivo
- Ninguna imagen rota: si Blender no encuentra el archivo de una textura, se exporta vacía y la entrega se rechaza
- ≤ 600 mil triángulos; ≤ 150 mallas tras unir; ≤ 25 materiales únicos
- Recorriste cada punto de vista en Blender (Numpad 0 con una cámara en el empty) — se ve compuesto, no accidental
---
9. Para desarrolladores
| Componente | Repositorio | Qué hace |
|---|---|---|
| Flow Manager Client (Google Apps Script) | flow-manager-client | los comandos de chat, el borrador en Google Doc, los callbacks |
| flow-mgr | flow-mgr | genera la propuesta, convierte y aloja la escena y los personajes, sesiones de voz (relay a Gemini Live), códigos de acceso, canal de formularios y pantallas |
wrk-mgr · interactive_web | wrk-mgr | empaqueta la experiencia (el shell web: workers/interactive_web/app_shell) y la publica en el origen de propuestas |
wrk-mgr · blender | wrk-mgr | convierte .blend/.fbx a glTF comprimido, audita escenas, convierte avatares |
| src-mgr | src-mgr | sincroniza las fuentes de Drive y sus etiquetas |
Teclas para el equipo (no se anuncian al cliente): Ctrl+Shift+K o ?tune abre el panel de ajustes (luces de la galería, subtítulos, animaciones de la presentadora, tarjeta de video, resolución de dibujo); los cambios se aplican al momento y Guardar los deja fijos para la unidad en el servidor. Ctrl+Shift+V enciende o apaga la presentadora en video para la unidad.
Documentación de referencia en los repositorios: wrk-mgr/docs/proposal-scene-spec.md (esta especificación), wrk-mgr/docs/workers/interactive-proposal.md (el shell y su contrato en tiempo de ejecución), flow-mgr/docs/proposals.md y flow-mgr/docs/live-relay.md (publicación, auditoría, voz, formularios). Los cambios al shell se despliegan como worker Modal interactive_web y se publican a cada unidad al republicarla.
---
10. El archivo de configuración de la escena
Un solo archivo por unidad, en formato TOML, en las fuentes de la unidad en Drive, cuyo nombre contenga scene config o configuración de la escena (mayúsculas y acentos no importan). Se lee al publicar y en cada /gen-proposal CODIGO --showcase. Reúne tres cosas: los ajustes del ejercicio (los mismos del panel de ajustes), una tabla por objeto de la escena bajo su nombre exacto de Blender, y las instrucciones de la guía. El antiguo documento de "temas del recorrido" ya no existe.
Cómo se combina con el panel (Ctrl+Shift+K): el archivo es la base; lo que se guarda en el panel queda encima, por unidad. Un valor largo (una instrucción) se edita con el botón … en una ventana grande. Las tablas de objetos aparecen en el panel como el grupo Objetos de la escena y también se pueden corregir y guardar ahí.
[quiz]
perStation = 2
passMark = 0.7
[tasks]
[prompts.rubric]
text = "..."
[scene]
welcome = "Bienvenido a la línea de inspección."
[Station_01_Placa]
task = "Revisa la placa: estencilado, medidas y espesor"
topic = "Qué se verifica en la placa y por qué importa"
description = "La mesa de placas a la entrada del molino: la placa sobre los rodillos, el micrómetro de 0-1\", las cintas y el reporte F-TUAC-022 en su tablilla"
questions = [["¿Qué datos del estencilado verificas?", "colada, proveedor y grado"], ["¿Con qué mides el espesor?", "con el micrómetro"]]
[Hotspot_Micrometer]
action = "Mide el espesor de la placa con el micrómetro"
reading = "12.50 mm"
[Clipboard_Inspeccion]
instructions = "Captura la colada y el espesor medido"
[Clipboard_Inspeccion.expected]
Espesor = "12.50"
[Show_Balde_De_Pintura]
note = "Pintura de marcado para identificar la placa aprobada"
10.1 Ajustes
Una tabla por grupo del panel; las claves son las del panel, anidadas como tablas o con punto (card.radius = "14px"). Valor por defecto entre paréntesis.
[render] — Resolución de dibujo
| Clave | Por defecto | Qué hace |
|---|---|---|
maxPixelRatio | 2 | Píxeles de dispositivo por píxel CSS en la galería (tope). |
walkMaxPixelRatio | 1 | El mismo tope dentro de la escena; 0.5 duplica los cuadros por segundo a costa de nitidez. |
powerPreference | "high-performance" | Pide la GPU dedicada en un portátil con dos (se aplica al recargar). |
[video] — Video de la presentadora (Kira)
| Clave | Por defecto | Qué hace |
|---|---|---|
layout.widthShare | 0.17 | Ancho de la tarjeta como fracción de la ventana. |
layout.minWidth | 132 | Ancho mínimo en px. |
layout.maxWidth | 288 | Ancho máximo en px. |
layout.aspect | 0.76 | Relación ancho/alto de la tarjeta. |
layout.margin | 16 | Margen al borde, px. |
layout.zoom | 1 | Escala del video dentro de la tarjeta. |
layout.focusY | 0 | Punto vertical del encuadre, 0–100 (0 = cabeza arriba). |
fade.hold | 3 | Segundos que la tarjeta se queda tras hablar. |
fade.fadeIn | 0.35 | Segundos de aparición. |
fade.fadeOut | 0.6 | Segundos de desaparición. |
servo.intervalMs | 30 | Cada cuánto se corrige la reproducción, ms. |
servo.onset.minLag / cushion | 0.5 / 0.3 | Al empezar a hablar: retraso mínimo para saltar al borde en vivo y colchón al que salta, s. |
servo.speaking.minLag / cushion / fromMs / untilMs | 0.6 / 0.3 / 40 / 200 | Durante el habla: un solo salto permitido entre fromMs y untilMs del inicio. |
servo.idle.minLag / cushion | 1.5 / 0.3 | En silencio: correa para que el video no se quede atrás. |
trim.after / behind / keep | 25 / 20 / 15 | Limpieza del búfer: cada cuántos segundos, cuánto detrás, cuánto conservar. |
codecs.native / baseline | avc1.42c01f… / avc1.42E01E… | Tipos MIME del flujo (no cambiar). |
card.radius | "0px" | Radio de las esquinas de la tarjeta (CSS). |
card.edge | "1px solid var(--tb-line)" | Borde de la tarjeta (CSS). |
[caption] — Subtítulos
| Clave | Por defecto | Qué hace |
|---|---|---|
holdAfterTurnMs | 2500 | Ms que el subtítulo se queda tras el turno, dentro de la escena. |
maxChars | 360 | Caracteres que se muestran (cortados al inicio de una frase). |
markdown | true | Mostrar negritas del modelo como negritas. |
maxAgeMs | 20000 | Dentro de la escena, el subtítulo se borra también pasado este tiempo desde sus últimas palabras, aunque el turno no haya cerrado. |
strayTokens | ["stdin"] | Palabras sueltas del modelo que se quitan del subtítulo. |
strayPatterns | ["response:…"] | Expresiones regulares de lo que el modelo filtra en sus palabras y no debe subtitularse (p. ej. el resultado de una herramienta). |
[presenter] — Animaciones de la presentadora 3D (Camila)
| Clave | Por defecto | Qué hace |
|---|---|---|
idle / talk / talkAlternate | "" | Nombres de clip a usar; vacío = los del modelo. |
swapSeconds | 9 | Segundos entre alternar clips de habla. |
crossfade.talkSwap / toTalk / toIdle / fadeOut | 0.6 / 0.35 / 0.45 / 0.6 | Segundos de fundido entre clips. |
clips | "" | Lista fija de clips (p. ej. "Idle"). |
[lighting] — Luces de la galería
| Clave | Por defecto | Qué hace |
|---|---|---|
toneExposure | 0.85 | Exposición ACES. |
envIntensity | 0.9 | Fuerza de la luz de entorno. |
key.intensity / key.position | 2.0 / [3, 6, 4] | Luz principal. |
fill.intensity / fill.position / fill.color | 0.45 / [-4, 2.5, 5] / 0xbfd0e0 | Luz de relleno. |
hemi.intensity / hemi.sky / hemi.ground | 1.0 / 0xdde7df / 0x37352f | Ambiente cielo/suelo. |
rim.intensity / distance / decay / position | 8 / 24 / 2 / [0, 3.4, -4] | Luz de contorno. |
[face] — Rostro de la presentadora 3D
| Clave | Por defecto | Qué hace |
|---|---|---|
roles.* | nombres de morph | Qué morph del modelo cumple cada papel (jaw, open, wide, smileL…). |
visemes.* | pesos | Mezcla de morphs por visema (AA, EE, IH…). Avanzado. |
[guide] — Guía dentro de la escena
| Clave | Por defecto | Qué hace |
|---|---|---|
gazeSilent | true | En el recorrido, la mirada es contexto silencioso, no un pie para hablar. |
turnStallMs | 12000 | Turno de ella sin audio por este tiempo = se da por terminado (modelo atascado). |
lessonStallMs | 45000 | Lo mismo mientras enseña una lección (el modelo hace pausas más largas entre sus partes). |
resumeAfterMs | 3000 | Si una lección se interrumpe y en este tiempo no se oyen palabras del cliente, fue un ruido: la guía retoma la lección desde la lámina en pantalla. |
describeForms | false | Al abrir una hoja, la guía la explica en voz alta (instrucción clipboardOpen). Apagado, solo se entera en silencio de qué hoja se abrió y puede contestar sobre ella. Mientras ella habla no se puede caminar ni accionar nada (girar y mirar alrededor, sí), pero una hoja siempre se abre, y durante una conversación con un personaje nada queda bloqueado. |
clickSkipsLesson | true | Mientras ella habla, un clic en el marcador de otra estación (en VR, el gatillo apuntando al marcador) la calla y lleva allí. Si estaba dando una lección, la estación dejada queda sin enseñar y sin completar: hay que volver a ella, y al volver la lección empieza de nuevo; lo que se accione en ella desde lejos no cuenta hasta volver. Mientras hace una pregunta de revisión, y en el examen, el clic espera. Apagado, el clic siempre espera a que ella termine. |
[gaze] — Mirada del visitante (solo en el recorrido: el ejercicio por tareas nunca usa la mirada)
| Clave | Por defecto | Qué hace |
|---|---|---|
enabled | true | Medir hacia dónde mira el visitante en el recorrido. |
tickSeconds | 0.5 | Cada cuánto se mide. |
coneDegrees | 8 | Cono de la mirada. |
minDistance / maxDistance | 2.5 / 12 | Distancias válidas, m. |
dwellSeconds | 5 | Segundos quieto mirando algo para contar. |
stillMove / stillTurnDegrees | 0.15 / 4 | Lo que cuenta como quieto (m, grados por medición). |
[tasks] — Ejercicio por tareas
| Clave | Por defecto | Qué hace |
|---|---|---|
enabled | true | Apagado = recorrido narrado, sin lista. |
requireInteractions | true | La tarea exige llegar y hacer todo lo que hay en la estación; apagado = llegar basta. |
stuckSeconds | 60 | Sin avance por este tiempo = un check-in de una frase (una vez por tarea). |
checkEveryMs | 5000 | Cada cuánto se revisa el reloj de atasco. |
maxTextChars | 160 | Largo máximo del texto de una tarea. |
summaryValuesChars | 300 | Caracteres de respuestas de formularios citados a la guía. |
startScreen | true | Pantalla de inicio al empezar el ejercicio: la frase de bienvenida, las tareas en orden y los controles; la guía espera a que se cierre. |
startScreenSeconds | 180 | Se cierra sola pasado este tiempo (o con un clic en cualquier parte). |
startLoadMaxS | 20 | Cuánto espera como máximo la pantalla inicial a que se precargue el material (las infografías) antes de mostrar «Haz clic en cualquier parte para empezar». |
startMusic | "industrial" | La música mientras está abierta: industrial (la de serie) u office (corporativa, de oficina); none = sin música. |
startMusicVolume | 0.5 | Su volumen, 0–1. |
startMusicFadeS | 1 | Segundos de desvanecimiento al cerrarla. |
[quiz] — Evaluación: preguntas y examen
| Clave | Por defecto | Qué hace |
|---|---|---|
enabled | true | Preguntas tras cada tarea. |
perStation | 2 | Preguntas por estación cuando el archivo no trae questions. |
exam | true | Examen final: las estaciones marcadas con exam = true otra vez, solo, en orden. Sin ninguna marcada no hay examen: las revisiones dan la calificación final. |
passMark | 0.7 | Mínimo (0–1) para aprobar una revisión y el examen. |
checksCount | true | El promedio de las revisiones también debe llegar a passMark para aprobar el examen; apagado, decide solo la práctica. |
nudgeSeconds | 45 | Sin calificación por este tiempo = un recordatorio a la guía. |
answerSeconds | 180 | Sin respuesta por este tiempo = la pregunta vale 0 y sigue. |
askSeconds | 20 | La pregunta de la guía no empieza en este tiempo (o se cortó antes de hacerla) = se le vuelve a pedir. |
askRetries | 2 | Veces que se le vuelve a pedir; después la tarjeta muestra la pregunta por escrito, del banco de la estación, y el cliente responde igual. |
clockTickMs | 5000 | Cada cuánto se actualizan los minutos del examen (y se revisa la edad del subtítulo). |
music | true | Música de éxito o de fallo mientras el informe está abierto; el informe (y su música) se abre cuando la guía termina sus palabras de cierre, no encima de ellas. |
musicVolume | 0.5 | Su volumen, 0–1. |
musicFadeS | 2 | Segundos de desvanecimiento al cerrar el informe, reiniciar o salir. |
musicDuck | 0.25 | Mientras la guía habla, cualquier música (la de inicio, la del resultado) baja a esta fracción de su volumen y vuelve al terminar. |
musicDuckS | 0.4 | Segundos de esa bajada y de la vuelta. |
musicSuccess | "assets/music/exam-success.mp3" | La pista de éxito (ruta relativa a la página de la unidad; vacía = una frase sintetizada). |
musicFailure | "assets/music/exam-failure.mp3" | La pista de fallo (igual). |
[sound] — Sonido
| Clave | Por defecto | Qué hace |
|---|---|---|
muteKey | "KeyX" | Tecla que silencia o activa todo el sonido (su voz y la música), igual que el ícono de bocina del diálogo; no actúa mientras se escribe. |
[mic] — Micrófono mientras ella habla
| Clave | Por defecto | Qué hace |
|---|---|---|
level | 0.025 | Nivel de salida que cuenta como su voz. |
tailMs | 400 | Ms que el micrófono sigue cerrado tras su voz. |
wholeTurn | true | Cerrado durante todo su turno, no solo mientras suena. |
turnMaxMs | 90000 | Tope de ese cierre por si un turno nunca termina. |
[listen] — Micrófono: cuándo escucha
| Clave | Por defecto | Qué hace |
|---|---|---|
windows | true | Dentro de la escena el micrófono abre solo cuando ella escucha. |
windowMs | 8000 | Ventana abierta tras cada turno de ella. |
heardExtendMs | 6000 | Prórroga mientras el relé oye hablar. |
holdKey | "KeyM" | Tecla que abre el micrófono mientras se mantiene. |
vrHoldButton | 4 | En el visor VR, el botón de control que abre el micrófono mientras se mantiene (índice del control estándar de WebXR: 4 = A en la mano derecha, X en la izquierda). |
vrCheckOpen | true | En el visor VR, mientras una pregunta de revisión espera la respuesta, ella escucha entre sus turnos (no hay dónde escribir); su propio turno sigue cerrado. |
[show] — Brillo de los objetos que nombra
| Clave | Por defecto | Qué hace |
|---|---|---|
eachS | 2 | Segundos que brilla cada objeto nombrado. |
videoLeadMs | 1200 | Con la presentadora en video: espera antes de encender (el texto llega antes que la voz). |
[markers] — Marcadores
| Clave | Por defecto | Qué hace |
|---|---|---|
riseRatio | 0.6 | A qué altura flota el marcador de una estación sobre el nivel de los ojos, como fracción de la estatura del visitante (0.2 lo dejaba delante de los estantes y de los puntos interactivos). |
hotspotRiseRatio | 0.2 | Lo mismo para el ícono de un punto interactivo, medido sobre el piso además de la estatura. |
ceilingMarginRatio | 0.1 | Si hay techo, los marcadores se quedan a esta fracción de la estatura por debajo de él. |
[actpip] — Primer plano de la acción
| Clave | Por defecto | Qué hace |
|---|---|---|
enabled | true | Mostrar el recuadro durante una acción. |
widthShare / minWidth / maxWidth / aspect / margin | 0.3 / 220 / 520 / 1.5 / 16 | Tamaño y posición del recuadro. |
frame | "equipment" | equipment encuadra lo que anima Play_; body encuadra al personaje. |
equipmentFill / equipmentMinDistance / equipmentSide / equipmentAbove | 0.6 / 0.35 / 0.6 / 0.45 | Encuadre del instrumento: llenado, distancia mínima, giro hacia la derecha del personaje, elevación. |
side / above / lookHeight / reach / fov | 1.9 / 0.2 / 0.7 / 0.45 / 38 | Encuadre del personaje (modo body): lateral, elevación, altura de mira, adelanto, campo de visión. |
[nav] — Navegación (caminos)
| Clave | Por defecto | Qué hace |
|---|---|---|
enabled | true | Con una Navmesh en la escena, un clic en una estación o un punto recorre un camino que rodea los Collider_; apagado (o sin Navmesh) = línea recta. |
cellM | 0.25 | Tamaño de celda de la cuadrícula sobre la Navmesh, m. |
maxStepM | 0.35 | Lo que se alza menos que esto sobre el suelo es un escalón, no un muro. |
headroomM | 1.7 | Altura del visitante: lo que haya por debajo en la celda la bloquea. |
radiusM | 0.35 | Medio ancho del visitante: las celdas bloqueadas crecen con él. |
margin | 2 | Metros de cuadrícula más allá del contorno de la Navmesh. |
budgetMs | 6 | Milisegundos por cuadro dedicados a construir la cuadrícula al entrar. |
maxCells | 200000 | Una Navmesh mayor usa celdas más grandes. |
speedMps | 2.2 | Velocidad del recorrido, m/s. |
minHopS / maxHopS | 0.5 / 8 | Duración mínima y máxima de un recorrido, s. |
snapM | 1.5 | Hasta dónde se mueve un extremo a una celda caminable, m. |
navmeshPrefix | "Navmesh" | Prefijo del objeto de Blender con la superficie caminable (ver la especificación de la escena). |
[characters] — Personajes: recorridos
Para los personajes con path (ver [Character_Nombre] en 10.2).
| Clave | Por defecto | Qué hace | ||||||
|---|---|---|---|---|---|---|---|---|
walkSpeed | 1.2 | Velocidad a la que camina un personaje su recorrido, m/s. | ||||||
walkClipSpeed | 1.4 | Velocidad a la que está hecha la animación de caminar; se reproduce a walkSpeed / walkClipSpeed para que los pies no resbalen. | ||||||
turnSpeed | 4 | Radianes por segundo que gira (hacia el camino, la silla o el visitante). | ||||||
fadeS | 0.35 | Segundos de transición entre una animación y la siguiente. | ||||||
occupyM | 0.6 | Un personaje a menos de esto del punto de una estación sigue en ella, m. | ||||||
besideM | 0.8 | Si el personaje no ha despejado la estación que eligió el visitante, este se detiene a esta distancia a un lado, m. | ||||||
occupied | "leave" | Lo que vale una estación que no dice occupied: "leave" o "inactive". | ||||||
sitDown / seated / standUp | "Sentarse" / "Trabajar" / "Levantarse" | Nombres de las animaciones de sentarse, de trabajar sentado (en bucle) y de levantarse; se buscan como las de act. | ||||||
lowerBody | `"Hip\ | Pelvis\ | Thigh\ | Calf\ | Knee\ | Foot\ | Toe"` | Huesos (patrón sobre su nombre) que se quedan en la silla cuando un personaje sentado habla; la animación de hablar mueve el resto. |
walkSrc / walkClip | /avatar-assets/shared/cc-animations-meshopt.glb / "Avatar_Walk" | La caminata compartida (de hombre). | ||||||
walkFemaleSrc / walkFemaleClip | /avatar-assets/shared/cc-walk-female-meshopt.glb / "Walk_F" | La caminata compartida de un personaje cuyo género es femenino. Una caminata entregada con el personaje gana a las dos. |
[lessons] — Lecciones por estación
Al publicar, el sistema escribe una lección por estación a partir del material de la propuesta y la configuración de la escena: título, objetivo, todos los puntos clave y pasos que el material da (sin límite), seguridad, las preguntas de la revisión con su respuesta, y un tablero de láminas (hasta slides): cada lámina tiene título, unas pocas etiquetas con las cifras y una infografía generada con el proveedor y modelo de imagen de [lessons]. Todas las infografías de la unidad reciben las mismas imágenes de referencia: las del material del cliente (las figuras de sus documentos y sus fotos), en su orden, hasta referenceImages; si el material no trae imágenes, ninguna se envía y la infografía se dibuja a partir de su descripción. La guía enseña la lección completa al llegar, lámina por lámina, nombrando cada una («Lámina 2: …»); al nombrarla, su infografía aparece sola en pantalla (sin marco, título ni controles), se queda showSeconds o hasta que nombra otra, y se desvanece; el botón Lección de la lista hace que la vuelva a enseñar entera desde el principio (sin marcarla, completarla ni revisarla de nuevo; elegir otra estación mientras tanto solo la calla). Sin infografías (dibujarlas está apagado por defecto: cada una se paga) no hay tablero y la lección no menciona láminas: la guía enseña las mismas partes, una por turno, cada una por su tema. Durante toda la lección el micrófono está cerrado: nada la interrumpe hasta que termina. Las preguntas de la revisión salen de la misma lección (salvo que la tabla de la estación traiga questions). La lección se vuelve a escribir solo cuando cambian el material, la configuración o la escena. Una infografía se dibuja solo cuando su lámina no tiene ninguna, o cuando el comando de publicación la nombra con --redraw: nunca por sí sola, ni porque cambie el texto de la lámina, el estilo, el proveedor o el modelo (cada imagen se paga).
| Clave | Por defecto | Qué hace |
|---|---|---|
enabled | true | Escribir una lección por estación al publicar. |
images | false | Dibujar las infografías que a las láminas les falten. Apagado salvo que se encienda aquí (cada imagen se paga). Las ya dibujadas se conservan y se muestran siempre; con --redraw se vuelve a dibujar lo nombrado aunque esté apagado. |
words | 150 | Palabras como máximo del texto de la lección (los guiones de todas las láminas juntos), solo sobre la estación; las preguntas salen únicamente de ese texto. |
slides | 4 | Láminas como máximo por estación. |
imageProvider | "openai" | Proveedor de imagen de las infografías (openai, gemini, bfl). |
imageModel | "gpt-image-2.5-sunburst" | Modelo de ese proveedor para las infografías. |
referenceImages | 4 | Cuántas imágenes del material se envían como referencia con cada infografía (las mismas para todas). |
questions | 2 | Preguntas de revisión por lección; el banco escrito tiene questionBank veces esta cantidad y la página elige al azar [quiz] perStation de él en cada revisión (una repetición no repite las preguntas). |
questionBank | 2 | Cuántas veces questions tiene el banco de preguntas de cada lección. Cada pregunta prueba un dato concreto de los guiones (valor, tolerancia, herramienta, documento, criterio, orden de pasos); la lección puede escribir menos que el banco antes que rellenar, y se descartan las preguntas que se responden solas, las que responde el nombre de la estación y las que ya hace otra estación. |
sourceChars | 60000 | Cuánto del material ve cada lección. |
board | true | Mostrar las infografías de la lección en pantalla. |
autoOpen | true | Armarlas solo al llegar a la estación (aparecen cuando la guía las nombra). |
showSeconds | 120 | Segundos que una infografía queda en pantalla si la guía no nombra otra. |
fadeMs | 600 | Milisegundos del fundido de entrada y salida (al cambiar de lámina, la anterior se desvanece antes de que entre la nueva). |
holdAfterTurnS | 8 | Segundos que la última infografía queda en pantalla después de que la guía termina la lección. |
preloadParallel | 2 | Cuántas infografías se descargan a la vez al entrar (todas juntas dejaban la música de inicio esperando). |
turnPerSlide | true | La lección va una lámina por turno: la página manda la lámina 1, y al terminar ese turno la 2, y así; cada infografía aparece cuando empieza el audio de su turno. Apagado, la lección entera va en un solo turno (el modelo lo corta a los ~170 s de audio). |
cueWords | ["lámina", "lamina", "slide"] | Palabras con las que la guía nombra una lámina y su número para que el tablero cambie. |
[telemetry] — Telemetría
| Clave | Por defecto | Qué hace |
|---|---|---|
enabled | true | La página envía su registro (decisiones, errores, ajustes, marcas) al registro de la sesión en el servidor. |
perf | true | Además mide el tiempo de cada cuadro (CPU por sección, GPU, cuadros lentos, tareas largas); apagar cuando no se esté midiendo. |
flushMs | 2000 | Cada cuánto se envía un lote. |
maxBatch | 60 | Entradas por lote. |
maxBuffer | 600 | Entradas guardadas mientras no hay conexión (se pierden las más viejas). |
maxChars | 500 | Largo máximo de un mensaje. |
errorsPerMinute | 20 | Errores de consola que se guardan por minuto. |
markKey | "KeyL" | Ctrl+Shift+esta tecla copia el id de la sesión y marca el momento en el registro. |
longTaskMs | 50 | Umbral de tarea larga del navegador (informativo). |
[prompts] — Instrucciones a la guía
Cada clave es una tabla con es y en (el texto de la instrucción en cada idioma); {n} es un número que la página rellena. rubric y protocolExtra llevan solo text.
| Clave | Momento |
|---|---|
enterTour | bienvenida al recorrido (sin tareas) |
enterExercise | bienvenida al ejercicio por tareas |
enterStation | bienvenida cuando el cliente aparece ya en la estación de la primera tarea: saluda y la enseña ({n} = frases) |
vr | bienvenida al visor de RV |
ar | la maqueta en realidad aumentada |
arExercise | la práctica con un personaje en RA |
station | llegada a una estación (recorrido) |
stationReached | llegada a la estación de una tarea sin lección escrita: improvisa la lección ({n} = frases) |
stationLesson | llegada a la estación de una tarea con lección escrita: la enseña completa |
lessonResume | una lección interrumpida por un ruido: la retoma donde la dejó |
lessonSkipped | se eligió otra estación durante una lección: calla, la estación queda sin enseñar y se enseñará de nuevo al volver; solo con [guide] clickSkipsLesson |
enterLessonSlide | bienvenida en la estación de la primera tarea con turnPerSlide: saludo de una frase y solo la lámina 1 |
lessonSlideFirst | llegada a una estación con lección y turnPerSlide: solo la lámina 1 |
lessonSlideNext | cada lámina siguiente de la lección (y la lámina actual tras una interrupción por ruido) |
lessonSlideResume | la lámina en curso, retomada donde una pregunta escrita la interrumpió |
typedQuestion | lo que el cliente escribe en el diálogo: respuesta corta, sin pregunta al final. Mientras una pregunta de revisión espera respuesta, lo escrito en el diálogo es la respuesta (como en la tarjeta de la pregunta) y va tal cual, sin esta instrucción |
enterLesson | bienvenida cuando el cliente aparece en la estación de la primera tarea y esta tiene lección escrita |
taskDone | tarea hecha, pedir la siguiente |
lastTaskDone | última tarea hecha, cierre (sin examen) |
checkOpen | abrir la revisión: confirmar y hacer la pregunta 1 ({n} = preguntas) |
checkNext | siguiente pregunta, tras enseñar la respuesta anterior |
checkDoneNext | revisión terminada, siguiente tarea |
checkDoneLast | última revisión terminada con alguna pregunta fallada: resultado final y el plan de estudio que la página arma con las láminas (por cada pregunta fallada: la lámina que la enseña, citada, y qué hacer en la escena); ella lo dice punto por punto |
checkDoneLastClean | última revisión terminada sin ninguna pregunta fallada: resultado final y felicitación, sin plan de estudio |
checkStuck | recordatorio: calificar o repetir |
examStart | anuncio del examen |
examDone | cierre con el resultado del examen y el plan de estudio que arma la página, cuando hubo alguna pregunta fallada |
examDoneClean | cierre con el resultado del examen sin plan de estudio: ninguna pregunta fallada |
checkIn | check-in tras inactividad |
act | qué está haciendo el cliente en un punto |
actDone | acción terminada |
showClick | describir un objeto al hacer clic |
clipboardOpen | hoja abierta: la enseña en profundidad (para qué sirve, cada campo y de dónde sale su dato, qué se hace con ella); solo con [guide] describeForms |
formUnfilled | hoja cerrada vacía |
comment | comentario breve (otros eventos) |
talkDebrief | retroalimentación tras conversar con un personaje |
awareness | prefijo de los contextos silenciosos |
rubric | text: la rúbrica de calificación |
protocolExtra | text: instrucción adicional al protocolo de la guía |
[controls] — Tablero de mando: teclas y funciones
| Clave | Por defecto | Qué hace |
|---|---|---|
functionDoneS | 1 | Segundos que una función de la máquina debe mantenerse activa para contar como hecha. |
keyDeflectPerS | 3 | Rapidez con que una palanca manejada con teclas llega al tope (desviación por segundo). |
keyReturnPerS | 4 | Rapidez con que vuelve al centro al soltar las teclas (salvo sticky). |
knobKeyPerS | 0.5 | Parte del recorrido de una perilla que gira por segundo con su tecla sostenida; una perilla con steps avanza una posición por pulsación. |
10.2 Objetos de la escena
Una tabla por objeto, con el nombre exacto del objeto en Blender ([Station_01_Placa], [Hotspot_Micrometer], ["Show_Balde_De_Pintura"]): así se emparejan. Las claves dependen del prefijo. Un nombre con acentos o espacios se escribe tal cual, con o sin comillas ([Show_Tapones_Para_Oídos], [Station_03_Mesa de herramientas]).
[Station_NN_Nombre / Seat_Nombre]
| Clave | Qué hace |
|---|---|
task | la tarea de la estación: lo que muestra la lista y lo que ella pide |
topic | el tema que enseña al llegar |
description | la estación en sí, en 2-3 frases: el lugar, los equipos, instrumentos y documentos que hay y lo que ve el alumno; es el escenario de cada lámina de la lección y ella lo cuenta al llegar. Sin esta clave se usan los hechos de la escena (número y nombre de la estación, los objetos que hay en ella y su nota de Blender); nunca la inventa un modelo. |
questions | lista de pares ["pregunta", "respuesta esperada"]; con ella hace exactamente esas, en orden |
images | true o false: false deja la estación sin infografías (ni las ya dibujadas); true dibuja las que le falten aunque [lessons] images esté apagado; sin la clave manda [lessons] images |
exam | true o false (por defecto false): la estación entra al examen final; sin ninguna estación con true no hay examen y las revisiones dan la calificación |
occupied | "leave" o "inactive" (por defecto [characters] occupied, "leave"): qué pasa cuando el visitante elige la estación y un personaje está en ella. "leave": el personaje sigue su camino (se levanta si está sentado y continúa desde su siguiente walk); si no ha despejado al llegar el visitante, este se detiene a un lado y cuenta como llegada. "inactive": mientras el personaje esté ahí la estación no se puede usar: su marcador se ve gris y no responde, y llegar caminando no cuenta (ni lección ni tarea) hasta que el personaje se vaya por su cuenta. |
[Character_Nombre]
| Clave | Qué hace |
|---|---|
note | lo que dice del personaje al nombrarlo o conversar |
path | su recorrido: pasos que repite en orden mientras el visitante está dentro de la escena (abajo) |
[Character_Alejandra]
path = [
{ act = "Saludar" }, # una animación, una vez
{ walk = "Archivo" }, # camina a esa estación por la Navmesh
{ act = "Buscar" },
{ walk = "Escritorio" },
{ sit = true }, # se sienta, mirando hacia donde mira el empty de la estación
{ work = [20, 60] }, # mantiene lo que hace (trabajar sentado o de pie) entre 20 y 60 s
{ stand = true }, # se levanta
]
- Los lugares son estaciones:
walknombra una estación por su nombre (ArchivoesStation_03_Archivo; mayúsculas y acentos no importan). Una estación que solo usan los personajes es una estación más que ningún ejercicio lista entask_stations([module..exercise.], en la documentación del player). act = "Nombre"busca la animación en este orden: la entregada para ese personaje, laAct_Nombrede la escena, y la importada para todos conscripts/character_clips.py import --act Nombre --url …. Sentarse, trabajar sentado y levantarse son animaciones de esos mismos nombres ([characters] sitDown / seated / standUp). Caminar: la entregada con el personaje, o la compartida (la de mujer si suGéneroes femenino).- El recorrido empieza al entrar a la escena y vuelve a empezar en cada entrada; en la galería y en el ejercicio en realidad aumentada el personaje queda quieto con su animación de reposo.
- Conversar lo pausa: si camina, se detiene y se voltea hacia el visitante; si está sentado, habla desde la silla. Al terminar sigue desde el mismo paso. Acercarse y oprimir E nunca lo hace irse.
- Una estación donde está el visitante, o a la que va, está tomada: el personaje cuyo siguiente
walkva ahí espera donde está hasta que el visitante se vaya. Lo que pasa al revés lo diceoccupiedde la estación (arriba). - Sin
Navmesh, camina en línea recta. Los personajes no se esquivan entre sí ni al visitante.
[Hotspot_Nombre]
| Clave | Qué hace |
|---|---|
action | qué hace el cliente al accionarlo (lo dice al empezar) |
reading | la lectura del instrumento; la dice al terminar la acción |
note | lo demás que debe decir al terminar |
[Clipboard_Nombre]
| Clave | Qué hace |
|---|---|
instructions | lo que dice al abrir la hoja |
expected | tabla campo = valor esperado, para que juzgue la hoja |
[Show_ / Screen_ / Button_ / Knob_ / Joystick_]
| Clave | Qué hace |
|---|---|
note | lo que dice del objeto al nombrarlo o hacer clic |
keys | solo controles: las teclas que lo manejan en la computadora. Una palanca lleva cuatro (arriba, izquierda, abajo, derecha: "ijkl"), una perilla dos (bajar, subir: "zx"), un botón una ("p"). Funcionan solo en la estación del control y con ninguna tarjeta abierta; las flechas, E, V y la barra espaciadora son de la escena y no se pueden usar. |
label | solo controles: el nombre corto que el mando imprime junto al control ("S1", "B2.RL"). El visor lo muestra flotando al lado del control, con una línea hasta él (ver «Primer plano del panel y etiquetas», abajo). Sin label, el control no lleva etiqueta. |
[scene]
| Clave | Qué hace |
|---|---|
welcome | su primera frase al entrar, tal cual |
Las tablas que solo usa el player de capacitación ([module.*], title en [scene]) y los avisos de /gen-player están en la documentación del player.
Sin tabla para un objeto, la página usa la propiedad note del objeto en Blender si existe, y si no, su nombre. Todo lo que hay en una tabla también llega a la guía como texto, así que puede contestar preguntas sobre ello.
Funciones de la máquina: [conditions] y [functions.Nombre]
En una máquina real, lo que hace la máquina sale de varios controles a la vez: las dos palancas hacia arriba avanzan las orugas; el botón de la palanca derecha sostenido con la palanca hacia adelante mueve el brazo; el regulador fija la potencia del martillo. Cada control mueve su propia acción Play_ (el control mismo, la mano del operador); lo que hace la máquina se describe aquí, una tabla por función.
[conditions]
listo = ["Button_S0 off", "Button_S1 on"]
[functions.Avanzar]
label = "Avanzar con las orugas"
when = ["listo", "Joystick_Torre.y > 0.2", "Joystick_Pluma.y > 0.2"]
plays = "Play_Orugas_Maquina"
follows = "Joystick_Torre.y"
[functions.Martillo_regulado]
label = "Martillar con potencia regulada"
when = ["listo", "Button_Percutor held", "Knob_R1 > 0"]
plays = "Play_Percutor_Maquina"
speed_from = "Knob_R1"
[functions.Avanzar_simultaneo]
label = "Avanzar con las dos orugas"
when = ["listo", "Knob_S5.step = 0", "Button_B1LR held", "Button_Alcance held"]
plays = ["Play_Oruga_Izq_Maquina", "Play_Oruga_Der_Maquina"]
drive = 1
Condiciones (en when y en [conditions]): el nombre de un grupo de [conditions], o un control con su prueba:
| Condición | Se cumple cuando |
|---|---|
Button_X on / Button_X off | el botón está encendido (mode = toggle) o mantenido; o no |
Button_X held | el botón se mantiene pulsado (mode = hold) |
Button_X | encendido o mantenido |
Knob_X > 0.5 | la perilla pasa de la mitad (0 = mínimo, 1 = máximo) |
Knob_X.step = 2 | la perilla con steps está en la posición 2 (0 = la primera): un selector |
Joystick_X.y > 0.2 | la palanca empujada hacia adelante (.y: −1 atrás, 1 adelante; .x: −1 izquierda, 1 derecha) |
Comparaciones: >, <, >=, <=, =. not delante niega una condición de control. La función está activa mientras se cumplen todas. Los nombres de los controles van tal cual en Blender, sin espacios.
| Clave | Qué hace |
|---|---|
when | lista de condiciones (obligatoria) |
plays | la acción Play_ de la máquina que mueve, o una lista de acciones que se mueven juntas (las dos orugas): ["Play_Oruga_Izq_Maquina", "Play_Oruga_Der_Maquina"] (obligatoria) |
follows | una palanca (Joystick_X.y) o perilla: la acción avanza a ese valor × speed por segundo, hacia atrás si es negativo; con la palanca a medias, a media velocidad |
drive | sin follows ni mode: un número de −1 a 1 (no 0); mientras la función está activa, la acción avanza a ese valor × speed por segundo, hacia atrás si es negativo. Es la función que mueve un botón: en el Brokk, con S5 arriba, B1.LR avanza las dos orugas (drive = 1) y B1.LL las hace retroceder (drive = -1). Una acción guarda una sola posición, la mueva una palanca o un botón |
speed | fracción de la acción por segundo a tope (por defecto, la del Joystick_: 0.5) |
speed_from | una perilla o palanca que multiplica la velocidad (el regulador). Mientras está en cero, la función no mueve nada ni cuenta como hecha. |
mode | sin follows: loop (por defecto) repite la acción mientras está activa; once la reproduce cada vez que se activa; hold avanza mientras está activa y regresa después |
rest | dónde está la máquina en reposo a lo largo de la acción, de 0 (inicio) a 1 (final). Por defecto, la mitad si la mueve una palanca o un drive (va en los dos sentidos, como las acciones de la palanca) y el inicio en los demás casos |
travel | true, con follows o drive: la acción lleva la máquina entera (mueve solo la raíz de su rig, como las orugas del Brokk) y la máquina va tan lejos como se la conduzca, desde donde esté, en vez de pararse al final de la acción. La detiene una pared u otro sólido, o una persona (el visitante o un personaje) a menos de 45 cm. El Collider_ que rodea la raíz de la máquina viaja con ella y es su huella; al reiniciar el ejercicio, la máquina vuelve a su sitio |
label | cómo se llama la función en la lista de tareas y para la guía |
note | lo que la guía sabe de ella |
station | la estación a la que pertenece (por defecto, la del primer control de when). Varias estaciones en un mismo lugar (a menos de 25 cm) son varias tareas que se hacen ahí sin caminar, en su orden; las teclas de un control fijo (un enchufe) funcionan en la estación de su lugar y en las que tienen funciones o estados que lo leen |
Cada función es un punto de la tarea de su estación: cuenta como hecha cuando se mantiene activa [controls] functionDoneS segundos. En una estación con funciones, los controles ya no son puntos sueltos ni avisan a la guía: la tarea es lo que hace la máquina. Las acciones de los controles deben mover solo el control (y la mano del operador); el movimiento de la máquina va en las acciones que nombran las funciones.
Las acciones de las funciones se suman. Al cargar la escena, el visor pone la máquina en la pose de reposo de cada acción (rest); cada función activa añade lo que su acción se aparta de esa pose. Así las dos palancas a la vez mueven la pluma y el brazo completos, aunque Blender exporte en cada acción todos los huesos del brazo y las mangueras se muevan en varias acciones. Si se reprodujeran enteras, cada una sostendría en reposo lo que mueve la otra y el visor las promediaría a la mitad. Lo mismo vale para los dos ejes de una palanca, que se suman desde el centro.
Estados de la máquina ([states.Nombre]): lo que la máquina recuerda, como la unidad de control encendida, el motor en marcha o el circuito de control establecido.
[states.encendido]
label = "Encender la unidad de control"
set = ["Button_S1 held"]
clear = ["Button_S0 on"]
[states.circuito]
label = "Establecer el circuito de control"
set = ["encendido", "Button_Alcance held"]
clear = ["not encendido"]
idle_s = 3
Un estado se enciende mientras se cumplen todas las condiciones de set y se apaga mientras se cumplen todas las de clear (si se cumplen las dos, se apaga). Con idle_s, se apaga solo cuando pasan esos segundos sin ninguna función activa: el circuito del Brokk se corta a los 3 s y el botón de la palanca lo establece de nuevo. Con hold_s, se enciende solo cuando sus condiciones de set llevan esos segundos cumpliéndose sin interrupción: el interruptor principal Q1 del Brokk, 3 s en la posición 0 antes de pasar a la otra fase. Con while, solo puede estar encendido mientras se cumplen todas esas condiciones: el motor, mientras la unidad está encendida y la máquina tiene corriente (clear exige todas sus condiciones a la vez, así que no podría apagarlo por cualquiera de las dos). Con last = true, un estado con label va en la lista después de las funciones: la desconexión es lo último. Con initial = true, empieza encendido. Una condición nombra un estado igual que un grupo de [conditions] (encendido, not circuito). Un estado con label es también un punto de la tarea: cuenta la primera vez que se enciende y va antes que las funciones en la lista, porque el arranque va primero. También acepta note y station.
Indicadores ([indicators.Nombre]): una luz del modelo, la malla Indicator_Nombre (u otra que diga node). Cada color (green, yellow, red, orange, blue, white) lleva la lista de condiciones que lo encienden; gana el primero que se cumple, y si ninguno se cumple la luz queda con su propio material.
[indicators.LED2]
green = ["circuito"]
yellow = ["encendido", "not circuito"]
Una pantalla muestra texto mientras está encendida: su tabla text asocia una condición (un estado, un grupo de [conditions] o una condición de un control, entre comillas) con lo que dice la pantalla en ese momento. Gana la primera que se cumple; si ninguna se cumple, la pantalla solo se ilumina. \n separa las líneas. El texto se dibuja como una pantalla con luz de fondo, con el color encendido de fondo y las letras oscuras. La malla necesita UV completa (la imagen llena la pantalla) con la parte de arriba de la pantalla arriba y su izquierda a la izquierda, como la ve quien la usa; con la UV volteada las letras salen al revés.
[indicators.Pantalla]
green = ["encendido"]
[indicators.Pantalla.text]
motor = "+23°C 20 bar\n102 h"
encendido = "BROKK\nStart Engine"
En lugar de un texto, una entrada de text puede ser una pantalla con la disposición de la de la máquina, como una tabla en línea:
[indicators.Pantalla.text]
motor = { lines = ["+23°C 20 Bar", "102 h"], left = "battery 4/4", right = "signal 4/4", mark = "lubrication" }
encendido = { logo = "BROKK", lines = ["START ENGINE", "(I) (M)"] }
| Clave | Qué dibuja |
|---|---|
logo | una palabra grande, en negrita y subrayada, arriba (la marca) |
lines | las líneas, centradas debajo |
left / right | un indicador de barras a lo largo de ese borde con su símbolo al pie: "símbolo nivel/de" (en el Brokk, la batería y la señal de radio, de 0 a 4 rayas) |
top | un indicador horizontal arriba, con su símbolo al principio (por ejemplo, el nivel de aceite) |
mark | un símbolo después de la última línea (por ejemplo, la lubricación del martillo) |
Símbolos: battery, signal, oil, lubrication, service. Todo se dibuja con la tinta oscura sobre el color encendido. La página dibuja la pantalla ella misma: no hace falta ninguna imagen.
Un indicador también acepta note (lo que la guía sabe de él) y label, su nombre corto ("LED2"), que se muestra a su lado como el de un control. Las luces de la máquina (sus faros de trabajo) también son indicadores: una malla Indicator_Luces que se enciende en white con el motor.
Primer plano del panel y etiquetas
Mientras el visitante maneja un panel (está en la estación de sus controles y ninguna tarjeta está abierta):
- En tercera persona aparece en la esquina inferior izquierda un primer plano del panel, visto desde los ojos del operador, con el lado lejano arriba, como en primera persona. La cámara de hombro no ve un mando colgado del cinturón, porque el cuerpo está delante. En ese recuadro no se dibuja a la persona, porque la cámara está entre sus ojos y el panel. Los controles llenan la mayor parte del recuadro: se encuadran por sus propias cajas, centrados, con margen para las etiquetas. Nada que quede entre la cámara y el panel lo tapa (una viga, por ejemplo). Mientras una animación
Act_se reproduce, su propio primer plano tiene prioridad. Con visor de realidad virtual no hay recuadro. - En primera persona, al mirar hacia abajo un mando que el visitante lleva puesto (en el cinturón), la vista se coloca sobre el centro del mando y retrocede lo justo para que quepa entero en la parte libre de la pantalla. Así se ve entero aunque el cuerpo se balancee al estar quieto. Al levantar la vista, la cámara vuelve a los ojos.
- Etiquetas: cada control o indicador con
labellleva su nombre flotando al lado, con una línea hasta él: en el primer plano en tercera persona y sobre la vista en primera persona. Cada etiqueta va del lado que da hacia fuera del panel si está libre y, si no, en el siguiente lado libre, sin tapar otros controles ni otras etiquetas. Sin un lado libre, toma el que menos estorba: una línea que cruza otra estorba más que tapar parte de un control, porque se lee como la etiqueta del otro. Dos etiquetas cuyas líneas aún se cruzan se cambian de sitio. Conserva su lado mientras siga libre, así que no salta cuando la vista se mueve un poco. - Un mando que se lleva puesto es el panel de su estación aunque en ella haya también controles fijos en la escena (el interruptor principal de la máquina, un enchufe): esos se accionan donde están, y el primer plano, sus etiquetas y el encuadre en primera persona son los del mando.
- El panel es lo que sostiene todos sus controles e indicadores: su padre común más cercano en el modelo (en el Brokk, el hueso
Controldel mando) más las mallas con skin solo a ese padre (la carcasa del mando). Si su padre común es todo el avatar o toda la escena, el recuadro encuadra solo los controles.
10.3 Avisos al publicar
| Aviso | Significado |
|---|---|
scene_config_missing | no hay archivo de configuración en las fuentes |
scene_config_invalid_toml | el archivo no es TOML válido (se ignora entero) |
scene_config_unknown_object | una tabla cuyo nombre no es un grupo de ajustes ni un objeto con prefijo conocido |
scene_config_unknown_key | una clave que ese tipo de tabla no admite |
scene_config_bad_value | un valor del tipo equivocado |
scene_config_stray_value | un valor suelto fuera de toda tabla |
scene_config_bad_path_step | un paso de path que no es act, walk, sit, work ni stand |
scene_config_bad_condition | una condición de when o de [conditions] que no sigue la forma de la tabla de condiciones (la función se ignora) |
character_path_unknown_station | un walk nombra una estación que la escena no tiene |
character_path_act_no_clip | un act sin animación (ni entregada, ni Act_ en la escena, ni importada) |
character_path_no_sit_clips | un sit sin las animaciones de sentarse: el personaje se queda de pie |
character_path_no_navmesh | un recorrido con walk en una escena sin Navmesh: camina en línea recta, atravesando lo que haya |
character_path_no_character | un [Character_…] con path pero sin personaje entregado |
---
ENGLISH
1. What it is
The interactive proposal is TrainBeyond's sales proposal turned into an experience: a private web page per client where a voiced virtual presenter walks through the proposal section by section and answers questions live, and where the client steps into a 3D scene of their own plant or operation to see, standing at real scale, what the training will give them. The same page works on a computer, a phone, a VR headset (Meta Quest) and, with passthrough, in augmented reality inside the client's own room.
Everything comes from three things:
| Piece | Who makes it | With what |
|---|---|---|
| The proposal text | sales, with AI help | the client's sources in Google Drive + an editable Google Doc |
| The 3D scene (optional, but it is what sells) | the 3D design team | a .blend or .fbx file following the naming conventions in this document |
| Publishing | operations | Google Chat commands (/gen-proposal, /audit-showcase) |
The result is one stable URL per unit (a 3-letter code such as FCA) protected by an access code given to the client. Republishing overwrites that same URL.
A unit's training as an app of its own (the training player on DEMO, with its module screen, its exercises and the LMS) has its own documentation: Training player.
2. What the client sees and does
2.1 Getting in
The client opens the link and types the access code (valid 180 days; the browser remembers it for 7). Inside, the gallery shows the proposal's panels in a ring around a diorama of the scene, and the presenter starts talking.
2.2 The presentation and the voice guide
- The presenter walks the sections; the client can pause and ask questions aloud (microphone button). She answers from the proposal and the unit's materials.
- Inside the scene the same voice speaks, but in her own session: the instructor's, which knows nothing of the sales proposal (no sections, budget or example videos; only the client's material and the scene configuration) and never sells. Entering closes the presenter's session and opens hers; leaving closes hers and the presentation comes back as it was: paused at its slide (▶ continues it) or with its questions open. The instructor: explains each station on arrival, points out objects, invites the client to try the interactions. She never interrupts herself: what happens while she speaks reaches her when she finishes. If the visitor stops to study something, she takes note but does not comment on her own.
?browseat the end of the address opens the proposal without the presentation, with the guide available for questions.- Video presenter. Per unit, the presenter can be real video (Gemini Live's Kira avatar) in a card in the bottom-left corner, in the gallery and inside the scene, instead of the 3D character. It is switched on at publish with
--video, or at any time with Ctrl+Shift+V inside the proposal (saved for that unit; the voice session restarts). Without video, the 3D presenter remains the fallback.
2.3 Inside the scene
The visit is a task exercise: the stations, in their order, are the tasks. Each one's instruction is the station's note, and what there is to do there are the interactive objects beside it (the hotspot, the sheet, the person, the screen, the controls). The guide asks for one task at a time, on arrival teaches the station and says what to do, confirms each task done, hints when the client gets stuck and closes with feedback. The checklist shows on the right, done tasks struck through; they can be done in any order. (The tuning panel can switch back to the narrated tour, or count a task done on arrival alone.)
Lessons. Every station has a lesson written at publish from the client's material and the scene configuration, with its infographic. On arrival the guide teaches it in full, one part per turn; with infographics, each one appears as she names it. The checklist's Lesson button has the guide teach it again from the start, changing no task. The check questions come from that same lesson.
Start screen. On entering the exercise (and after a reset) a screen shows the welcome line, the mission (the tasks in order, with their station's number and name) and the controls, with its own music. The guide falls silent the moment it opens (even mid-sentence) and says nothing until it closes: a click anywhere on it, or by itself after three minutes (a setting). The checklist and the dialog stay hidden while it is open, so the screen shows alone.
Assessment. When each task is done, the guide asks two short questions about that station, drawn from what she just taught (the proposal's material and the scene configuration). When she finishes asking, a card appears in the middle of the screen with her words, a line to type the answer and an I don't know button; while the check is open the client cannot walk or work anything. They answer aloud (the microphone opens when the question ends) or by typing; she scores each answer from 0 to 100 and the checklist shows each question's score and the station's average ("100 · 0 → 50 %", green when it passes, red when not). A grade counts only after the client has spoken or typed; if the guide grades before that, the grade is discarded and she repeats the question. While the check is open nothing else reaches the guide. A question unanswered for three minutes scores 0 and the next one comes. After each answer she says what the correct one was and why: one sentence if right, two if wrong. The rubric (100 complete and correct · 80 one minor omission · 60 the main idea · 30 related but wrong · 0 wrong or no answer; judged only against the proposal's material) and every instruction the page gives the guide are in the tuning panel, group "Instructions to the guide", saved per unit. The card appears once the action has fully finished and she has finished asking. When a hotspot is worked, the guide says in a sentence what the client just did and confirms it is done. While the action plays, an inset shows up close the instrument or part the animation moves, so its reading can be read; if the point carries a note with the reading, she says it when done. With every task done and checked comes the exam: the client repeats the whole exercise alone, in the correct order, with no checklist, no station numbers and no help; the guide stays silent until the end. Reaching a station means walking up to it (or using its marker, outside the exam); the station where the exam begins counts only after walking away and coming back. It is passed by completing every task with at least 70% of them in order and with the station checks' average at or above that same pass mark (setting checksCount; off, the practical alone decides). The report shows both parts with their own result. At the end she closes with the exam result, the check results and brief feedback, and the exam report opens: passed or not, tasks in order, time, and each station's check score with their average (green passes, red fails); the success or failure music plays while the report is open. The report closes or restarts the exercise; the result's Report button reopens it. If the client leaves the scene with the report open and comes back in, the report shows again, with Close and Restart; reloading the page starts the exercise over. (Questions per station, the exam and the pass mark are settings in the panel.) The final report fills most of the screen, in three tabs: Summary (result, score and score per station), Study plan for the next attempt, which the page builds from the slides themselves (per missed question: the slide that teaches it, quoted, and what to do in the scene: replay that slide with the Lesson button and click the station's objects), and Questions and answers (every question with your answer, the correct one, the feedback and the lesson sentence that teaches it). The Download PDF button saves the same report as a PDF file; the box “Include the full session transcript in the PDF” (unticked by default) appends the whole session's dialog at the end of the PDF, with the lines that cover the study plan's topics highlighted and the topic named under them. When the report is closed the exercise data stays in the browser: in the configuration panel (Ctrl+Shift+K), “Report: saved data” opens the last report again, saves the data to a file and loads a report from a file, without repeating the exercise.
The microphone inside the scene has two states, open and closed, and the badge at the top right says which. It opens only when the guide is listening: for a few seconds after each thing she says, and for as long as the client keeps talking. While walking, with a sheet open or while she explains, it is closed, so the room's noise never reaches her. To speak to her at any other time, hold the M key or click the badge. A VR headset has no keyboard and no badge: hold A or X on either controller, and a small sign below the view says whether the mic is open ("Listening") or how to open it. While a check question waits for its answer, in the headset she listens between her turns without any button (in VR there is nowhere to type the answer).
| Action | Computer | VR headset |
|---|---|---|
| Enter the scene | click the diorama | Enter VR button |
| Look | drag with the mouse | turn your head |
| Walk | arrow keys (the ground is followed: steps, ramps; walls, posts and machines stop the visitor) | thumbstick; teleport by pointing at the floor |
| Change station | click the numbered marker: the character walks there around obstacles | point at the marker and pull the trigger |
| Start over | Reset button on the checklist or the report: everything goes back to the start (tasks, worked points, sheets, screens, position at station 1) and the entry runs again: start screen, welcome and lesson (asks to confirm) | same |
| Report a problem | Ctrl+Shift+L copies the session id and marks the moment in the log; send it with what happened | same |
| Skip to the check (testing) | Ctrl+Shift+X ends the current station's lesson, takes its task as done and opens the check | same |
| Know where you are | the status bar shows the station's number and name ("Station 1 · Placa"); the marker of the station you stand on shows grey and still while its task is pending; the guide names stations by their number, as the markers do | same |
| Bird's-eye view | space bar | — |
| Change view (third / first person / drone) | V | — |
| Activate a nearby interactive point | E, or click the diamond | trigger on the diamond |
| Next image on a screen | click the screen | trigger |
| Talk to a character | E near them, or click | trigger |
| Speak to the guide | opens by itself after each thing she says; at other times, hold M or click the badge | opens by itself after each thing she says and for a whole check question; at other times, hold A or X |
| Press a machine button / turn a knob / move a joystick | click / drag or wheel / drag | trigger / hold the trigger and raise or lower the hand or use the thumbstick / hold the trigger and use the thumbstick |
| Open a form | click the clipboard: the camera comes close and the page appears alone over it | filled in from a phone (?clipboard) |
| Leave | Esc. On re-entry the visitor stands at the station they left and the exercise's progress is kept; Reset returns them to station 1 | — |
With a delivered Avatar, the client tours the scene as a character (third person by default); in VR they see their own body from the neck down and, with hand tracking, their real hands drive the avatar's.
2.4 Special addresses
| Address | What for |
|---|---|
https://…/FCA/ | the proposal |
https://…/FCA/?clipboard | on a phone or tablet: the scene's forms, to fill in while someone else sees them in the headset |
https://…/FCA/?display | on a computer: shares its screen to the scene's Display_ monitors (same network) |
https://…/FCA/?browse | no presentation; just the scene and the guide |
2.5 Augmented reality
On a headset with passthrough, View in your room (AR) places the diorama on a real table. With a delivered character (--character), Practise in your room (AR) puts that person life-size in the client's room, with a screen in front, to practise a conversation.
3. How a proposal is produced
3.1 Sources in Google Drive
Each unit has its folder under the sales root (Sales Drive). What is in there feeds the text, the guide and the scene:
| What | Where / how it is recognised | What it feeds |
|---|---|---|
| Client documents, meeting notes, images | the unit's folders; the folder gives the label (from-client, meeting-notes…) | the proposal draft and the guide's context |
| Scene configuration | a TOML file whose name contains scene config or configuración de la escena | the unit's settings, one table per scene object and the guide's instructions (see chapter 10) |
| 3D scene | the file passed to --showcase | the diorama and the inside view |
| Presenter avatar | folder with a Character Creator 4 FBX export, passed to --avatar | the presenter in 3D |
| Practice character | files passed to --character, --persona, --idle, --talk | a person the client talks to |
| Form pages | .html files in a forms folder or beside the client's documents | the scene's Clipboard_ planes |
| Example videos | shared video-samples / trainbeyond folder | the examples gallery |
3.2 The commands
Typed in Google Chat, in the Flow Manager space. CODE is the unit code: 3 alphanumeric characters.
Step 1 — generate the draft
/gen-proposal FCA
/gen-proposal FCA --es --high
Generates a draft with AI and saves it as the Google Doc "FCA Proposal" in the unit's sales folder. --es fixes the proposal language as Spanish (default is English); --high asks for a more thorough draft. Running this step again regenerates the Doc and discards the edits.
Step 2 — edit the Doc
Whatever stays in the Doc is what ships. Inside a section you can add special lines:
<<panel-image: https://drive.google.com/file/d/1AbC.../view | Cutting line overview>>
<<examples: https://drive.google.com/file/d/1Vid1.../view | https://drive.google.com/file/d/1Vid2.../view>>
<<examples-exclude: https://drive.google.com/file/d/1Vid3.../view>>
<<examples: none>>
<<panel-image: URL | Caption>>: a design image on that panel (a link-viewable Drive file; one per section).<<examples: …>>: keeps only those example videos, in that order;examples-excludehides the listed ones;examples: noneremoves the gallery.- A real page break (Ctrl+Enter) controls printed pagination.
Step 3 — publish
/gen-proposal FCA --publish
/gen-proposal FCA --es --publish --interactive
Publishes the Doc verbatim (no AI). --interactive also publishes the 3D experience with the live presenter. --video leaves the video presenter (Kira) switched on for that unit; without it, the 3D presenter. Repeat --es so the narration and the guide speak the right language. The chat reply carries the URL and the access code for the client.
The 3D scene
/audit-showcase https://drive.google.com/file/d/1AbC.../view --project FCA
/gen-proposal FCA --showcase https://drive.google.com/file/d/1AbC.../view
/gen-proposal FCA --es --publish --interactive --showcase https://drive.google.com/file/d/1AbC.../view
- Audit first (
/audit-showcase): opens the delivered file, inspects it and reports in chat. Read-only: nothing is converted or published. Pass the unit as--project. --showcasewith the link to the.blend,.fbxor.glb(or a folder holding one): converts the file, hosts it and makes it the diorama and the inside view. Without--publishit republishes the existing proposal with the new scene; with--publish --interactiveit publishes everything together..--redrawdraws lesson infographics again: alone (--redraw) orall, every one; a station by name, label or number (--redraw placa,--redraw 1); one slide (--redraw placa:2); several, comma-separated (--redraw placa:2,mesa)- Delivering the same unchanged file again converts nothing.
Presenter avatar
/gen-proposal FCA --avatar https://drive.google.com/drive/folders/1Fem.../
A Drive folder with the Character Creator 4 FBX export. The folder name must contain female or male: that picks the voice. Without --publish it republishes the existing proposal with the new avatar.
A character to practise a conversation with
/gen-proposal FCA --publish --interactive \
--character https://drive.google.com/file/d/1Alej.../view \
--persona https://docs.google.com/document/d/1Pers.../edit \
--idle https://drive.google.com/file/d/1Idle.../view \
--talk https://drive.google.com/file/d/1Talk.../view
--character: a Character Creator 4 export (.fbx, T-pose, no animation;CC_Base_*bones; a Mixamo character is refused).--persona: a Google Doc withName:,Persona:,Lines:,Voice:(orGender:) lines.Persona:andLines:open multi-line sections;Lines:are the facts and sentences the person says word for word.--idle/--talk: motion-only.fbxclips on the Character Creator skeleton (from Character Creator, iClone or ActorCore); a Mixamo clip is retargeted at publish. Optional: without them the last imported clips are used.- With a scene, the
Character_Alejandraobject marks where they stand; without one the person appears in the client's room (AR).
Example persona Doc:
Name: Alejandra
Gender: Female
Persona: Hotel receptionist, 8 years in the job, friendly but firm on protocol.
Lines:
Good morning, welcome to Hotel Foliatti, do you have a reservation?
Check-in starts at 3 pm.
Other
/gen-proposal --help
/audit-showcase --help
/flow status --project FCA
3.3 What a publish returns
In chat: the sources used, image jobs, the interactive proposal URL and the access code. Each unit has one URL; republishing replaces it in place, without interrupting anyone who has it open.
4. Naming conventions — quick reference
The viewer is not configured: it reads the object and action names in the Blender file. Anything that matches no convention is plain scenery. Names are compared trimmed and case-insensitively; the separator can be _ or ..
| Name | Type | What it does | Example |
|---|---|---|---|
Station_NN_Name | empty on the floor | standing viewpoint; NN orders; entered at the lowest; its −Y faces forward | Station_01_Reception, Station_02_Cutting_Line |
Seat_Name | empty at eye height | seated viewpoint (cab, control chair); limited look | Seat_Crane_Cab |
Skybox | mesh (inverted dome) | the sky and the ambient light; hidden in the diorama | Skybox |
Sun | Sun-type light | direction and colour of the shadows (the viewer sets the strength) | Sun |
Loop_Name | action | ambient animation looping while the client is inside | Loop_Conveyor, Loop_Flare |
Avatar + Idle, Walk | armature + actions | the client tours the scene as that character | Avatar, Avatar_Eyes (optional empty at eye height) |
Hotspot_X / Play_X / Act_X | empty / scene action / avatar clip | interaction: the anchor where they stand, the equipment moving, the human gesture | Hotspot_Open_Valve, Play_Open_Valve, Act_Open_Valve (Act_Operate = generic gesture) |
Focus_Name | object or empty | what the diorama frames when the ground is huge | Focus_Airliner |
Screen_Name_NN | stacked meshes | screen with an image sequence; a click advances | Screen_Menu_01, Screen_Menu_02 |
Display_Name | 16:9 mesh | monitor showing live the screen shared with ?display | Display_Registration |
Character_Name | empty or root | where a person the client can talk to stands; properties persona, voice, gender | Character_Alejandra |
Clipboard_Name | mesh in the paper's shape | a form the client fills in; property form = HTML page (or fields) | Clipboard_Inspection + form = corte.html |
Show_Name | object | lights up when the guide says its name (whole words, only those at the current station); optional note | Show_Helmet, Show_Nitrile_Gloves |
Collider_Name | simple mesh (box or plane) | invisible stop for the visitor where steps would pass through railings, guardrails or cables; never drawn | Collider_North_Rail |
Button_Name | mesh or empty over meshes | machine button; plays Play_Name; property mode = once / toggle / hold / latch | Button_Start + Play_Start |
Knob_Name | mesh or empty over meshes | knob; scrubs Play_Name from minimum to maximum; property steps | Knob_Pressure + Play_Pressure |
Joystick_Name | mesh or empty over meshes | two-axis stick; drives Play_Name_X and Play_Name_Y; properties mode (position / rate), sticky, speed, tilt | Joystick_Boom + Play_Boom_X, Play_Boom_Y |
Indicator_Name | mesh | a machine light that glows in the colour the configuration file says ([indicators.Name]) | Indicator_LED1 |
Custom properties (Object Properties → Custom Properties) the viewer reads:
| Object | Property | Example |
|---|---|---|
Station_ / Hotspot_ | note — the station's topic the guide expands | Every coil is inspected here before cutting |
Show_ | note — one sentence about the object | Protects against chemicals |
Character_ | persona, voice, gender | Receptionist, 8 years…, Kore, female |
Clipboard_ | form (HTML page), fields (A; B; C... list), note | corte.html · Name; Date; Notes... |
Button_ | mode (once, toggle, hold, latch), plays (another action) | toggle · Play_Pump |
Knob_ | steps (fixed positions), value (where it stands when the scene loads, 0 to 1), plays | 5 · 0.5 |
Joystick_ | mode (position, rate), sticky (no spring back), speed (action per second at full push), tilt (degrees) | rate · 1 · 0.5 · 20 |
Several objects in one action: NLA tracks with the same name on each object (Play_Start on the button and on the piston) export as one animation. That is how the button sinks and the machine answers, or the knob turns and the needle follows.
Bone constraints (machines): the viewer solves these constraints of the scene's armatures live, as Blender does: Damped Track; Copy Location and Copy Transforms between bones of the same armature, in world space; IK of one or two bones without a pole (with its bones' IK locks and limits); Limit Rotation and Limit Location in local space. So with several actions at once (the boom and the arm), the cylinders keep aiming at their mounts, the hoses follow their control points and the tool stays on its mount. Actions should move only the bones that are really animated (boom, arm, tool, slew): what the constraints follow, the viewer places. Other constraints stay as each action bakes them, and the conversion log names them (BLEND_BONE_CONSTRAINTS).
A panel on the visitor's body: a remote the operator wears (on the belt) is parented in Blender to a bone of the Avatar (Bone parent type). It travels with the visitor, shows in first person when looking down, and its controls work with the pointer, the controller ray in VR or their keys. First person looks out of the middle of the open part of the screen, left of the checklist and dialog column: what the operator faces, the remote when looking down, is not under that column.
5. Forms (Clipboard_)
The form is an HTML page the designer writes: any layout, the plant's sheet as a table, inline styles, even a script that builds the rows. Rules:
- Every box the client fills in is an
<input>,<select>or<textarea>with aname. - The file goes with the unit's Drive sources: in a
formsfolder, or beside the client's documents (from-client). It is found by its name (e.g.corte.html). - In Blender, the
Clipboard_Inspectionplane carries the custom propertyform = corte.html(formsworks too; on the object or on its mesh data). Model it in the paper's shape (landscape or portrait).
Minimal example:
<!doctype html>
<html lang="en"><meta charset="utf-8">
<style>body{font:12px Arial;padding:10px} td,th{border:1px solid #333;padding:2px} input{width:100%;border:0}</style>
<body>
<h2>Inspection · Cutting line</h2>
<label>W.O. <input name="wo"></label> <label>Date <input name="date" type="date"></label>
<table>
<tr><th>#</th><th>Length</th><th>Defects</th></tr>
<tr><td>1</td><td><input name="row1_length"></td><td><input name="row1_defects"></td></tr>
<tr><td>2</td><td><input name="row2_length"></td><td><input name="row2_defects"></td></tr>
</table>
</body></html>
How it is used: on a computer, a click on the clipboard opens the page inside the proposal; in a headset or on a tablet, a phone opens …/FCA/?clipboard and every form in the scene appears there. What is typed shows on the paper for everyone in the scene. Without a page, fields = Name; Date; Notes... generates a plain form (... = multi-line). Full examples: docs/examples/clipboard-forms/ in the wrk-mgr repository.
6. Machine controls (Button_, Knob_, Joystick_)
- Name the control
Button_StartorKnob_Pressure(a mesh, or an empty with the control's meshes under it). - Create the action
Play_Start/Play_Pressurewith keyframes of the control and of what it moves: the button sinking and the piston rising; the knob turning and the needle following. - Export.
| Control | Behaviour | Properties |
|---|---|---|
Button_ | plays the action once when pressed | mode = toggle: repeats until pressed again, then rests · mode = hold: runs forward while held, back on release · mode = latch: runs to the end and stays there (on) until pressed again, which runs it back (an emergency stop pushed in and pulled out) · plays = Play_Other to use another action |
Knob_ | scrubs the action: start = minimum, end = maximum; turned by dragging, with the wheel, or in VR holding the trigger and raising/lowering the hand (or with the controller's thumbstick) | steps = 5: fixed positions · value = 0.5: where it stands when the scene loads (a three-way selector starting in the middle) · plays |
Joystick_ | two axes over Play_Name_X / Play_Name_Y (centre = the middle of the action); the stick tilts by itself; springs back on release; moved by dragging or, in VR, holding the trigger and using the controller's thumbstick | mode = rate: the action runs while pushed and stays when let go (crane, boom) · speed = 0.5 · sticky = 1 · tilt = 20 |
A knob's action is one pose per value, no cycles. A hotspot is still the choice when the avatar should walk to the equipment and make a gesture.
A panel with several controls. One panel can carry several buttons, knobs and joysticks at once, of any kind. Each needs its own name and its own action (Button_Start + Play_Start, Button_Stop + Play_Stop, Joystick_Boom + Play_Boom_X / Play_Boom_Y): two controls on one action move together. Each control counts as one item of its station's task, Blender copies included (Button_Stop and Button_Stop.001 are two items). In VR each hand works its own control: the joystick in one, the hold button in the other.
What the machine does with several controls at once (both sticks to drive, the stick's button with the stick for the arm, a mode selector, an emergency stop) is described in the configuration file, in [conditions] and [functions.Name] (chapter 10.2). On a computer each control can have its keys (keys) to work two sticks at once.
7. The audit (/audit-showcase)
Checks the delivered file before importing it. The report arrives in chat as several messages: a summary, then findings by severity.
| Severity | Findings |
|---|---|
| 🛑 Blocking (do not import) | linked_libraries_missing, image_has_no_pixels, images_not_packed, no_entry_points, reserved_loop_prefix, scene_scale_suspect |
| ⚠️ Warning (something is missing) | hotspot_without_clip, act_without_hotspot, single_entry_point, skybox_not_emissive, backdrop_not_emissive, sun_not_directional, focus_frames_nothing, screen_frame_unnumbered, screen_frames_misaligned, screen_single_frame, character_without_persona, character_voice_unknown, character_not_rigged, clipboard_without_fields, clipboard_not_a_mesh, clipboard_not_a_plane, collider_not_a_mesh, control_without_clip, control_not_a_mesh, mesh_without_material, names_with_stray_whitespace |
| 💡 Note | cutout_uses_alpha_blend, opaque_material_carries_alpha, avatar_idle_clip_missing, avatar_walk_clip_missing |
Each finding comes with what it is and how to fix it, in the language of --es.
8. Full scene specification
Audience: 3D design team
Deliverable: one interactive scene per proposal, shown inside the client's interactive proposal
Format: .blend (Blender 4.x or 5.x up to 5.2, preferred) or .fbx — deliver the source file, we handle all export and optimization
What's new in v1.1
- Revised budgets: more triangles (≤ 600k), but new hard limits on meshes and materials — those are what actually decide performance. See the table.
- Embodiment avatar (
Avatar+Idle/Walk/Act_*clips): the client tours the scene as a character, in third or first person. - Interactions (
Hotspot_+Play_+Act_*): points where the client operates equipment — opening a valve, pushing a button. - v1 scenes without an avatar or hotspots remain 100% valid; the new sections are optional (but highly recommended).
- Viewer support for the avatar and interactions is in development — deliver scenes now regardless; the pipeline validates the names from day one.
What you are building
The scene appears twice in the proposal, from the same file:
- Diorama — a tabletop-scale model at the center of the proposal gallery, like an architect's scale model. This is what the client sees first.
- Inside view — clicking the diorama puts the client inside the scene at full scale: standing at locations you define, seated at eye points you define (vehicle cab, control chair), or touring it as a character (
Avatar) in third or first person. The AI presenter narrates while they explore.
Design for both scales. The scene must read as an attractive miniature from above AND hold up at eye level from every viewpoint you place. Detail what a standing person will look at; don't detail what nobody will ever be near.
Hard requirements
| Rule | Detail |
|---|---|
| Units | Real-world meters. 1 Blender unit = 1 m. A door is ~2.1 m, a handrail ~1.0 m. |
| Transforms applied | All object scales applied (Ctrl+A → All Transforms) before delivery. |
| Materials | Principled BSDF only. Procedural textures baked to image textures, max 2048×2048, and at most ~24 texture images total — atlas repeated props. Texture memory is the scarcest resource on target devices. |
| Animation | Keyframed actions staged on NLA tracks. No physics sims, cloth, or particles — bake them to keyframes if needed. |
| Geometry budget | ≤ 600,000 triangles total (aim ~450k). Spend triangles where the client will be standing; the Avatar (~20–40k) counts inside the total. |
| Object budget | ≤ 150 meshes after joining (join everything that shares a material) and ≤ 25 unique materials. This budget decides frame rate more than triangles do — spend meshes and materials like money: a 600k-triangle scene in 120 meshes outperforms a 250k one in 600. |
| Self-contained | Pack all textures into the file (File → External Data → Pack Resources). No linked libraries. Packed file ≤ ~150 MB. |
We compress everything (geometry and textures) after conversion — you do not need to optimize file size beyond the budgets above.
Naming conventions — how your scene talks to the viewer
The viewer reads object names and animation (action) names to know how to behave. Objects that don't match any convention below are ordinary scenery.
Station_NN_Name — standing viewpoints (empties)
A place a person can stand. Add one empty per location, positioned on the floor (we raise the camera to the avatar's measured eye height automatically, and a station that is not on its floor is reported by /audit-showcase instead of being silently moved). The empty's rotation sets the initial view direction (its +Y axis is "forward" — enable Display As: Arrows to see it).
NN= two-digit tour order (01,02, …). Clicking the diorama enters at the lowest number.Name= human-readable label, CamelCase or hyphenated. The AI presenter says this name out loud — writeStation_02_ControlRoom, notStation_02_stn2final.- Visitors can hop between stations inside the scene, so place them where the tour makes sense: entrance → key areas → payoff view.
- The empty is authoritative. The viewer stands the visitor exactly where you put it and corrects nothing, so it must be resting on the floor.
/audit-showcasemeasures everyStation_against the real floor and tells you before import if it is not. - Add more than one. A single station means there is nowhere to navigate: no jump markers appear and the visitor only ever sees one thing.
Seat_Name — seated viewpoints (empties)
A locked, seated view: cockpit, crane cab, control chair. Position the empty at the exact eye point of the seated person (not the floor). The visitor can look around from there but cannot move.
Skybox — the sky (mesh, optional)
A large inverted sphere or dome, emissive material, equirectangular sky texture, surrounding the scene. Hidden while the scene is a diorama; revealed when the client steps inside. If you skip it, the viewer supplies a plain default sky — a real one is always better.
The sky image is wired to Emission, not Base Color. The viewer bakes the dome into an environment map inside a scene with no lights: a dome with its texture on Base Color bakes black and the whole scene goes dark (AER shipped this way). /audit-showcase reports it as skybox_not_emissive.
Loop_Name — ambient animation (action names)
Any action whose name starts with Loop_ plays automatically, forever, once the client is inside: Loop_FlareStack, Loop_Conveyor, Loop_Traffic. Make the first and last keyframes match so the loop is seamless.
Demo_Name — the first page's demo (action names, optional)
A training's first page (the player's module screen) shows the whole training area as a miniature: every station, seat and hotspot with the subject. Its walls and roof are cut 2.2 m above the highest floor the trainee stands on. What moves there is up to you:
- With
Demo_actions. Every action whose name starts withDemo_plays there, all together, with theLoop_actions. - They start at the same moment and start again when the longest ends; a shorter one holds its last frame until then.
- The name after
Demo_is free, and may repeat with Blender's suffix (Demo_Controls.001). - If one of them moves the avatar, it shows where you placed it in the file; if none does, it is not shown.
- Without
Demo_actions. The avatar goes through the exercise, round after round, while theLoop_actions keep running. - It walks from station to station, in their order. At each one it goes to its hotspots and makes their gesture (
Act_) while the equipment moves (Play_). - Several stations one after the other on one spot are one stop.
- It walks on the
Navmeshwhen there is one; otherwise straight, as in an exercise. - At the end of the round it walks back to the first station and starts another.
- None of this happens inside an exercise. On entry everything goes back to its starting pose, and
Demo_actions never play there.
In ALF the demolition demo is Demo_: the operator at the remote (Demo_Operador, Demo_Controles), the Brokk hammering the wall (Demo_Brokk_v3) and the wall's 50 pieces falling (Demo_Pared_Trozo_033_0…). TAC has no Demo_: its first page shows the avatar touring its five stations, using the micrometer and writing.
Avatar — the client's character (armature, optional)
A character the client "embodies" once inside: they can see it in third person (over-the-shoulder camera), look through its eyes in first person, or release it and fly free (drone mode, the current behavior). If the scene has no Avatar, the viewer works exactly as before — drone mode only.
- The root armature is named
Avatarand all its meshes live under it. Its position in the file doesn't matter — the viewer spawns it at the entry station — nor where its bones sit relative to its origin: the viewer centres it on its feet (the skeleton's root). - Avatar clips (staged on NLA like everything else):
Idle(optional) — standing loop.Walk(optional) — walking in place (no root motion), at a natural ~1.4 m/s cadence; the viewer syncs playback speed to actual movement so feet don't slide.- If the
Avatarcarries noIdleorWalk, the viewer uses shared ones (a man's stance and walk, on the Character Creator skeleton). Clips the scene brings always win: include them when the scene needs its own, for example for a woman's avatar. Act_Name(optional) — one-shot actions for interactions (see hotspots). A genericAct_Operateserves as the fallback for any hotspot without a specific clip.Avatar_Eyes(empty, optional) — the exact eye point; defines the first-person camera *and the standing eye height at everyStation_**. Parenting it to the head bone is preferred, but we also read it if it sits loose in the scene. If absent we use ~94% of the avatar's measured height.- Meshes that must disappear in first person (face, hair, lashes, glasses) are named with the
Head_prefix (Head_Face,Head_Hair). With noHead_meshes, the viewer hides the whole avatar in first person. - Hidden at diorama scale, like the
Skybox. Its triangles count against the budget (~20–40k is typical).
Hotspot_Name — interactions (empties) — the name triad
A point where the client does something: open a valve, push a button, inspect a panel. An interaction is defined by up to three pieces that share exactly the same name:
| Piece | Type | Role |
|---|---|---|
Hotspot_OpenValve | empty in the scene | The anchor (required): the exact position and orientation where a person would stand to do it, with +Y toward the equipment. |
Play_OpenValve | scene action | The equipment side: the wheel turns, the panel lights up. It plays once when triggered and holds its last frame (an opened valve stays open; a prop the action hides at the end stays hidden). What shows before the trigger is the object's base pose: a prop that should exist only during the action has scale 0 as its base. |
Act_OpenValve | avatar clip | The human side: the reach-and-turn motion. |
Viewer behavior: approaching (~2.5 m) surfaces the prompt; on trigger the avatar glides onto the anchor and Act_ + Play_ play together, then it returns to Idle. While the action plays, an inset shows up close what Play_ animates (the instrument, the valve): model the reading legibly and leave the animation on the value to be read. reading in the [Hotspot_Name] table of the configuration file (or a Blender note property) has the guide say the reading when done. That's why the anchor matters: place it exactly where the feet should be and the hand will land on the equipment. Without an avatar (or in drone mode), clicking the marker plays Play_ alone — hotspots work in every scene, avatar or not.
- Interaction clips: ≤ ~10 seconds.
- The name is shown on screen and the AI presenter speaks it —
Hotspot_OpenValve, notHotspot_hs01.
Focus_Name — the diorama's subject (object or empty, optional)
Tell the viewer what the diorama is showing. In the gallery the scene is a diorama: the viewer scales it so its largest extent measures about 4 m. When a scene needs far more surroundings than subject — FER's cab has windows front and back, so the rails and the floor must run a long way in both directions — the surroundings own that scale and the subject ends up tiny.
- Name the main object
Focus_Name(Focus_Train). If the subject is several objects, parent them under an empty with that name: everything under it counts. SeveralFocus_*objects frame their union. - The diorama is scaled to and centred on the
Focus_, not the whole scene. The rest of the surroundings keeps its real size and, in the diorama only, is trimmed to a round base a little wider than the subject, like a model railway on its plinth. - Inside the scene nothing is trimmed: the rails and the floor are all there, at full scale, as far as you modelled them.
- A
Focus_with no mesh under it frames nothing, and the viewer goes back to measuring the whole scene;/audit-showcasereports it asfocus_frames_nothing. - Without any
Focus_everything works as before: the scene's largest extent rules.
Icon_Camera — the module icon's view (camera, optional)
/gen-player renders the LMS module's icon from this file: a 1080 px square image, like the other modules' icons. Without a camera it frames the diorama's subject (Focus_, or the whole scene) from behind and above the first station, leaving out whatever stands between the camera and the subject (a railing, a cabin's panels). To choose the view yourself, add a camera named Icon_Camera: it is used as it is. The avatar, the Skybox (the sky is neutral, as in the diorama), Collider_ objects and the Navmesh never appear in the icon. The light is the viewer's: the file's Sun and a neutral sky that nothing but the subject blocks, so a subject inside a cabin stays lit.
Screen_Name_NN — screens with image sequences (meshes)
A monitor, tablet or kiosk that shows a series of images (the screens of a registration system, say). Model the screen as a plane carrying the first image and duplicate it in place once per image: Screen_Registration_01, Screen_Registration_02, … each copy with its own image in the material (wired to Emission, so it reads as a lit display under any lighting). The viewer shows only _01; a click, a tap or the VR trigger on the screen advances to the next image and wraps around after the last.
- Frames must match exactly in position and size (Shift+D without moving);
/audit-showcasewarns when one drifted. - Number from
_01with no gaps. A frame without a number (Screen_Menu) is ordinary scenery; a screen with a single frame does nothing when clicked. - Every image counts against the texture budget; export the captures at 2K or less.
- The voice guide knows which screen the client is looking at and which image it is on; describe each screen in the tour-topics document (under the screen's name) and the guide comments on it.
Display_Name — live display (mesh)
A monitor that shows a computer's screen live: the client's real software (their registration system, say) running while the client practises in front of the character. Model the monitor as a 16:9 plane with a full UV (the image fills the plane) and name it Display_Registration. Whatever material you give it is what shows while nobody is sharing.
- The sharing computer opens the proposal with
?displayat the end of the address and presses Share this screen; from then on everyDisplay_*in the scene shows that screen. Both machines must be on the same network. - One plane per monitor; several
Display_*planes show the same image. - For a fixed image sequence use
Screen_;Display_is for live software.
Character_Name — people the client can talk to (empty or root)
A person in the scene the client practises a real voice conversation with: a guest at the reception desk, a customer at the counter. The character is not modelled in the scene: the operations team delivers it on the publish command, like the showcase:
/gen-proposal UNIT --publish --showcase <scene> --character <model> --persona <doc> --idle <clip> --talk <clip>
--character: the Character Creator 4 export of the character (.fbx, T-pose, no animation): the same standard as the presenter.--persona: a Google Doc withName:,Persona:(who they are, what they want),Lines:(optional: what they say and the details they give — phone, e-mail, address — one per line; the person uses them word for word, never invents others) andVoice:(malePuck,Charon,Fenrir,Orus; femaleAoede,Leda,Zephyr,Kore) orGender:lines.Persona:andLines:span the lines that follow; name, voice and gender take one line each. Every character speaks with a voice different from the guide's.--idle/--talk: motion-only .fbx clips on the Character Creator skeleton (exported from Character Creator or iClone, or bought on ActorCore): standing loop, and while speaking. A Mixamo clip is retargeted onto the CC skeleton at publish. Without these flags the last imported clips are used.
Your part in the scene is the spot: an empty (or any object) named Character_Name where the person stands, with the same Name as the persona doc, facing where the client will be. The viewer puts the delivered model there and hides the marker. Within ~2.5 m the prompt E — 💬 Name appears; E, a click or the VR trigger starts the conversation and the guide stays quiet; it ends with E again, another click, walking away (> 4 m) or the person saying goodbye, and the guide comments on how it went.
- Without a scene (
--characterand no--showcase), the person appears life-size in the client's room through the Practise in your room (AR) button, with a generatedDisplay_screen in front of them. - With a scene, on a passthrough headset that same button places the person and the
Display_*planes in the client's room; the scene is turned so the person facesStation_01. - Action paths (optional): instead of staying on its spot, the person can follow a path between stations — greet, walk to the filing room along the
Navmesh, sit at the desk, work a while, get up and repeat; a conversation pauses it. It is written in the configuration file (pathin[Character_Name], see chapter 10 of the proposal system guide). A station only characters use is one moreStation_NN_Namethat no exercise lists in itstask_stations; where the person sits, that station's empty faces the way the seated person looks. Its actions are the scene'sAct_Nameanimations (the same as theAvatar's) or imported separately.
Clipboard_Name — forms the client fills in (mesh, optional)
A clipboard with a form the client fills in during the practice: a new-customer registration, an incident report, the plant's own inspection sheet. Model the clipboard as a plane with full UV, in the paper's shape (portrait or landscape), and name it Clipboard_Registration. The material you give it is what shows when nobody is in the scene; inside, the viewer draws the form with what is being typed.
- The form is an HTML page you write: any layout, the plant's sheet as a table, inline styles, even a script that builds the rows. Every box the client fills in is an
input,selectortextareawith aname. Keep the page with the unit's sources in Drive (in a folder namedforms, or beside the client's documents) and put its name in the object'sformcustom property (corte.html;formsworks too, and the property may sit on the object or on its mesh data). A full address works too, and so does the page itself inside the property. Ready examples indocs/examples/clipboard-forms/. - Without a page: a list of fields in the
fieldsproperty, separated by;(Name; Date; Notes...; a field ending in...is multi-line) makes a plain form. Optional:note, one sentence on what the form is for. - How it is filled in: on a computer, a click on the clipboard opens the page inside the proposal; in a headset or on a tablet, open the proposal on a phone with
?clipboardat the end of the address and every page in the scene appears there. What is typed shows on the paper for everyone in the scene (a picture of the page; external stylesheets and images stay out of the picture, hence inline styles). - The voice guide only hears about a form when it is part of a task (see The stations are the tasks): on submit, or on close with every field filled in.
/audit-showcasereports aClipboard_with neitherformnorfields, one that is not a mesh, or one that is not a plane (clipboard_not_a_plane): a modelled clipboard or a whole computer with that name is not painted — the paper or the screen needs its own plane. - Inside the showcase, touching the clipboard brings the camera close to the object and the page appears alone over it, with no frame; closing it returns the camera.
Show_Name — objects the guide points out one by one (objects, optional)
For a station with several objects the guide explains one at a time — PPE on a table, tools on a bench — name each object Show_Name (Show_Helmet, Show_Nitrile_Gloves). While the guide talks about an object it glows orange; moving on to the next one turns the previous one off.
- Each
Show_belongs to the nearest station (Station_orSeat_): just name the objects on the table, nothing has to be parented. - The name is what the guide says aloud; write it the way it is spoken, with underscores between words.
- Optional: a
notecustom property on the object with one sentence about it (Protects against chemicals); the guide expands it while describing it. - If the object is several pieces, parent them under an empty named
Show_: everything under it glows. - The guide decides the order as it talks; the glow lasts while it describes the object and turns itself off after a few seconds if nothing changes it.
- A click on the object lights it and the guide describes it (again, if need be), with its
notewhen it has one. - The object lights up when the guide says its name: that is why the name must be what one says about the object (
Show_Nitrile_Gloves, notShow_Obj17). - The name is recognised as whole words, in order:
Show_Chalklights on "the chalk" or "chalks", not on a word that merely contains it. Little words (of, the, a) may be added or dropped ("leather gloves" counts forShow_Gloves_Of_Leather); a number is said as written in the name ("20 metres" forShow_Tape_Measure_20_metres, so write it the way the guide will say it). When one name is contained in another (Show_GlovesandShow_Leather_Gloves), the longer wins where all of its words are said. - Only the objects at the station the client is standing at can light up: a tool on the next bench that shares a word with one here does not take the glow.
Navmesh — the surface to walk on (mesh, optional)
When the visitor goes to a station or an interactive point with a click, the character walks a path on the scene's Navmesh, around tables, railings and rollers instead of through them.
Add a mesh named Navmesh (or Navmesh_Plant, anything starting that way) with the walkable surface: aisles, platforms, ramps. The viewer hides it on load (never drawn, no shadow, not a stop) and builds a floor grid from it. Only Collider_ objects block cells above it: the rest of the scenery is not read, so give everything the visitor must walk around a Collider_. Between cells the path never climbs or drops more than a step.
- One mesh or several; they only need to sit level with the real floor (± a step).
- Without a
Navmesh, a click goes in a straight line. - Settings in the panel and in the configuration file, group
nav: cell size, step height, the visitor's width, walking speed.
Collider_Name — invisible stops for the visitor (meshes, optional)
The visitor collides with the scene's meshes (six horizontal rays, ankle to head). Where the geometry leaves gaps between those rays — a guardrail's bars, a railing, a cable, a very thin showcase — place a simple box or plane named Collider_Name (Collider_North_Rail) over the zone that must not be crossed. The viewer hides it on load: it is never drawn, casts no shadow, is not a floor and cannot be pointed at; only the visitor's steps feel it.
- Leave it visible in Blender with any material; the viewer hides it.
- One box per stretch is enough; it need not follow the object's shape.
/audit-showcasereports aCollider_that is not a mesh (collider_not_a_mesh).
Door_Name and Open_Name — doors that open and are walked through (mesh or root, and an action, optional; v1.6)
A door is the object Door_Name (Door_Storeroom): the leaf as a mesh, or a root with the leaf under it. Its scene action Open_Name (Open_Storeroom) opens it: the viewer plays it forward to open and backward to close, and it holds its last frame.
- A click on the door opens it; another closes it. Shut, the visitor bumps into it and routes (a marker click) do not pass its doorway; open, it is walked through.
- The
Navmeshmust run through the doorway: the shut door closes it by itself. - A door with no
Open_action does not open: it stays a wall (the viewer says so in the console). - To another exercise (PROP-60): with the custom property
exerciseon the door (the code of an exercise of the same module, or its suffix:PR), the door is locked until the trainee completes the current exercise; it then opens and, walked through, starts that exercise (its start card inside the scene). While locked, a click says what is missing.
Button_Name, Knob_Name and Joystick_Name — controls on a machine (meshes, optional)
Buttons, knobs, levers and gauges the client operates right on the equipment: press the start button and the conveyor runs; turn the pressure knob and the gauge needle follows. They need no anchor and no avatar: the client works them from wherever they stand, with a click, the headset trigger or a hand.
- Name the control
Button_StartorKnob_Pressure(a mesh, or an empty with the control's meshes under it). What it does lives in the actionPlay_Start/Play_Pressure: there, as keyframes, goes both the control's own motion and the motion of what it drives — the button sinking and the piston rising; the knob turning and the needle following. Several objects in one action: NLA tracks with the same name, exactly as for a hotspot'sPlay_. To use another action, put its name in theplayscustom property. Button_plays the action once when pressed. With themodeproperty:toggle(the action repeats until pressed again; switching off returns everything to rest),hold(runs forward while held and back when released) orlatch(runs to the end and stays there until pressed again, which runs it back: an emergency stop pushed in and pulled out; its action ends with the button in).Knob_scrubs the action: its start is the knob at minimum, its end at maximum. It turns by dragging with the mouse (or the wheel), or in the headset by holding the trigger and raising or lowering the hand. Thestepsproperty (5) gives it fixed positions, andvalue(0 to 1) says where it stands when the scene loads:steps = 2andvalue = 0.5is a three-way selector starting in the middle.Indicator_is a light on the machine (a mesh): it glows in the colour the configuration file says ([indicators.Name]), from the machine's state; dark, it shows its own material. If it is a display that shows words ([indicators.Name.text]), give it a full UV: the image fills the display, with the top of the display at the top and its left at the left, as its user sees it (a mirrored UV shows the words backwards).- A
Knob_'s action must be one pose per value, no cycles: each point of the action is one position of the knob and of what it indicates. Joystick_has two axes and drives two actions:Play_Name_X(left → right) andPlay_Name_Y(back → forward); the middle of each action is the stick centred. Model the stick with its pivot at the base: the viewer tilts it by itself (tiltproperty, degrees; 20 by default). By default each axis scrubs its action like a knob (mode = position); withmode = ratethe action runs while the stick is pushed and stays where it is when let go — a crane boom that keeps slewing while the stick is held (speedproperty: fraction of the action per second at full push, 0.5 by default). Letting go springs the stick back to centre, unlesssticky = 1. It is moved by dragging with the mouse, or in the headset by holding the trigger on it and using the controller's thumbstick; that thumbstick also turns a held knob.- Several controls on one panel. A panel can carry several
Button_,Knob_andJoystick_together. Each control has its own name and its own action: two controls on one action move together. Each is one item of its station's task, Blender copies included (Button_StopandButton_Stop.001are two items with the same label). The control under the pointer (or under the controller's ray in VR) is worked, never its neighbour; in VR each hand holds its own control. What the machine does with several controls at once (both sticks, a button with the stick, a selector) is not in Blender: it goes in the configuration file ([functions.Name]), which names the machine'sPlay_action. So each control's action moves only the control and the operator's hand. A machine action driven by a stick has the machine at rest in its middle, like the stick's own actions; the others at their start (or whererestsays). The actions of several functions add up, so they may share bones, like hoses that follow both the boom and the arm. For the machine to travel freely (tracks), its action moves only the rig's root and the function hastravel = true: the machine goes as far as it is driven. Put aCollider_round the machine: it travels with it, stops it at walls and people, and the visitor bumps into the machine wherever it is. A cable between two parts (from the machine to its power source) is an emptyCable_Namewith the propertiesfromandto(the names of the two parts it joins),radius(metres, 0.012 by default) andcolor: the viewer draws it from each end down to the floor and along it, and draws it again when an end moves (the machine travels, the plug is pulled). - Bone constraints. The viewer solves a machine armature's constraints live, as Blender does: Damped Track, Copy Location and Copy Transforms (between bones of the same armature, world space), IK of one or two bones without a pole, Limit Rotation and Limit Location (local space). Cylinders, hoses and the tool stay in place with several actions at once. Animate only the bones that really move; the constraints place the rest.
- A remote on the visitor's body. Parent the remote (its
Button_,Knob_,Joystick_andIndicator_) to a bone of theAvatar: it travels with the visitor and works the same. Its housing may be skinned to that same bone. In third person the viewer shows a close-up of the remote in a corner, seen from the operator's eyes; it frames the controls' common parent plus the meshes skinned to it alone. In first person, looking down, the view moves over the remote so all of it fits. The controls' short names (labelin the configuration file) float beside them, in that close-up and in first person. - Two buttons on one stick. Each button is its own
Button_with its own action, a child of the stick so it tilts with it (on the Brokk,Button_Percutoris B1.LL andButton_B1LRis B1.LR, side by side on the left stick's head). /audit-showcasereports a control without itsPlay_action or one that is not a mesh.
Lights
Your Skybox is the scene's main light. The viewer bakes it into an environment map (IBL), and that is where all ambient light and every metal reflection comes from. It is the same thing Blender's world does, and it is the biggest lever you have over how the scene looks. A well-exposed sky lights the scene well; a flat or dark one leaves everything dull.
The Sun decides where shadows fall. The viewer takes its direction and colour, not its intensity: Blender exports W/m² converted to lux and the viewer rescales again, so intensity does not survive the trip usefully. The viewer sets its own strength, calibrated against exposure. Aim the Sun how you want the shadows and ignore its Strength value.
The first Sun (directional light) in the scene is the one used; a second sun is not switched on. Point and spot lamps are: in the player, inside the scene at full size, every one you place lights at the strength you gave it (in the miniature they are off, since that close they would burn it out). For an interior they are the light that counts: light it the way you want it to look.
It has to be a Sun-type lamp: a Point or Area light named "Sun" does not count (AER shipped a 17.8-million-candela point and the viewer ignored it — no sun direction, no authored shadows). /audit-showcase reports it as sun_not_directional.
The ground must not set the diorama scale. In the gallery the scene is shown as a diorama: the viewer scales the scene's largest extent (Skybox and Avatar excluded) to 4 m. A ground plane or apron much larger than the subject becomes the whole diorama and the subject turns tiny (AER's airliner rendered 0.8 m on a 185 m apron). Trim the ground to the walkable area, or — when the scene needs those surroundings, like rails that must look long from the cab — name the subject Focus_Name and the ground stops counting. /audit-showcase reports it as diorama_fit_dominated.
Until 2026-08-14 this section claimed every light lit the inside view. It did not: the converter never exported them. Fixed.
The stations are the tasks (nothing new to name)
The visit is not a stroll: it is a task exercise, and the tasks are your Station_NN_Name (then the Seat_) in their order. Nothing has to be added:
- Each task's instruction is
taskin the[Station_NN_Name]table of the scene configuration file (see the system guide, chapter 10); without it, the station's Blendernoteproperty; without either, its name. - What there is to do there are the interactive objects nearest to that station — the same rule as
Show_: theHotspot_, theClipboard_, theCharacter_, theScreen_or the controls standing beside it. - The task is done when the visitor reaches the station and does everything there: works the hotspot, clicks every
Show_object, hands in the sheet or closes it answered (everyrequiredfield when the page marks any, else something changed on it; afieldssheet wants all its fields and has a Submit button; closing it untouched earns a reminder from the guide; aClipboard_with neitherformnorfieldsdoes not count), ends the conversation, advances the screen to its last image, works the control. A station with nothing to do is done on arrival. - Several tasks at one place. When several tasks are done where the visitor already stands (the Brokk: switching it on, its tracks, its arm and its hammer, all from the operator's spot), put their
Station_NN_Nameempties on the same spot (within 25 cm of each other). The visitor does not walk between them: when a task is done, the next one at that place starts right there, with its lesson and its questions. One marker shows per place, the due task's. The machine's functions and states choose their task withstationin the configuration file.
The guide asks for one task at a time, on arrival teaches the station and says what to do there, confirms each task done, hints when the visitor gets stuck and closes the exercise with brief feedback. A checklist on screen shows the tasks, done ones struck through; they can be done in any order.
After each task the guide asks two questions about the station (only about what she taught on arrival; the lesson comes from the scene configuration file and the material) and grades the answers. At the end, the exam: the whole exercise again, alone, in order, with no markers and no checklist; the guide stays silent until the close. None of this is named in Blender.
How the viewer uses your scene
- The camera enters at the delivered avatar's own eye height over the
Station_empty exactly where you put it (no raycast, no self-healing):Avatar_Eyesminus the bottom of the rig's bounds. With noAvatar_Eyeswe use ~94% of its measured height; with no avatar at all, 1.7 m.Seat_points are honored exactly. - The client can look (drag), turn and walk (arrow keys — the camera follows the terrain: curbs and stairs work, but the ground can only lift a visitor by about a knee, so a roof overhead is never walked onto), toggle a bird's-eye view (space bar), and hop between stations (numbered markers).
- With an
Avatar, the client enters in third person and can switch third person / first person / drone mode. The avatar obeys the same ground rules as the camera. - In VR, the visitor sees their own body from the neck down: the body follows the headset (physical steps included), turns when the visitor turns — not when they merely glance — and blends Idle/Walk from actual ground speed.
- Hand tracking (IK): with bare hands (no controllers), the visitor's REAL hands and fingers drive the avatar's arms and fingers. For this to work the rig must keep: (1) the exact Character Creator
CC_Base_*bone names — no renaming or retargeting on export; (2) theT_Poseclip in the export; (3) metre scale, in-place animations; (4) a single armature underAvatar. When the visitor lowers their hands (out of the headset's cameras), the arms ease back to the animation — expected behaviour, not a bug. - Near a
Hotspot_*the interaction prompt appears; the viewer glides the avatar onto the anchor before playing the clips. - A click (or the VR trigger) on a
Screen_advances it to the next image; near aCharacter_, E (or a click) opens a voice conversation with that character, who speaks with its own voice. - Design consequence: the ground between stations should be walkable and continuous; compose each station as a shot, but remember the client can walk away from it.
- Coming soon: the same scenes will also be explorable in VR headsets (Quest). No extra work on your side — but real-world meter scale and the performance budgets matter even more.
Delivery and feedback
Deliver the file the same way as any showcase model (Drive link to the operations team). The publish pipeline validates the scene automatically and reports problems by name in the chat card — e.g. "Station_03 sits 4.2 m above the ground — stations belong on the floor" or "scene is 17 m wide but declares walkable stations — rescale to meters." Fix and re-deliver; re-publishing is cheap and the model is reconverted only when the file actually changes.
Before anything is imported, the operations team can ask for a check with /audit-showcase <drive link>: it opens your file without converting or publishing it and answers in chat with what it found — missing linked libraries, images Blender could not load, hidden objects that would never reach the export, clip names outside the conventions, the scene budgets, and since September 2026 also whether the Sun is directional, whether the Skybox is emissive, and which object sets the diorama scale. If something is off you hear about it in minutes, without touching the client's proposal. The card shows the first six affected items of each finding; the full report (every texture with its size and the materials using it, hidden objects, stations against their floor) is at the link at the end of the card.
Two cases are rejected outright, because the client would open an empty scene: a file with no geometry (what a master file whose linked libraries were not delivered with it produces) and a texture with no pixels (an image whose file Blender could not load). The message names the objects that did arrive, or the materials affected.
Pre-delivery checklist
- 1 unit = 1 meter; all scales applied; scene is real-world size
- At least one
Station_(orSeat_) empty, on the floor (seats: at eye point), forward direction checked - Station and hotspot names are presentable — the AI presenter speaks them
Skyboxdome present (or consciously skipped), image wired to Emission- One Sun-type lamp (not point/area) aimed the way you want the shadows
- Ground or apron no more than ~1.5× the subject's size, or the subject is named
Focus_Name— otherwise the ground sets the diorama scale - Ambient motion staged as
Loop_*NLA actions, seamless - Optional: the first page's demo staged as
Demo_*actions; without them the avatar tours the stations and their hotspots - If you include an
Avatar: head meshes prefixedHead_;Avatar_Eyeson the head bone (recommended);IdleandWalkon NLA only if the scene needs its own (Walkin place, no root motion) - Hotspots: anchor where the feet go, +Y toward the equipment; the
Hotspot_X/Play_X/Act_Xtriad shares the exact name - Screens:
Screen_X_01,_02… duplicated in place, one image per frame (Emission), numbered with no gaps - Live display:
Display_X, a 16:9 plane with a full UV - Characters to talk to: a
Character_Xempty where the person stands (the model, persona and clips arrive with--character,--persona,--idle,--talk) - Objects described one by one at a station: each named
Show_Name, optionally with anote - Forms the client fills in:
Clipboard_Nameplanes with the HTML page inform(or a list infields) - Invisible stops where steps would pass through railings or cables:
Collider_Nameboxes - Machine controls:
Button_X/Knob_Xwith theirPlay_Xaction (the control and what it moves, in one action);Joystick_XwithPlay_X_X/Play_X_Y - Principled BSDF everywhere; procedural textures baked; textures ≤ 2K, ≤ ~24 images, packed into the file
- No broken images: if Blender cannot find a texture's file it exports empty and the delivery is rejected
- ≤ 600k triangles; ≤ 150 meshes after joining; ≤ 25 unique materials
- Walked every station/seat viewpoint in Blender (Numpad 0 on a camera at the empty) — it looks composed, not accidental
9. For developers
| Component | Repository | What it does |
|---|---|---|
| Flow Manager Client (Google Apps Script) | flow-manager-client | the chat commands, the Google Doc draft, the callbacks |
| flow-mgr | flow-mgr | generates the proposal, converts and hosts the scene and characters, voice sessions (relay to Gemini Live), access codes, the form and display channels |
wrk-mgr · interactive_web | wrk-mgr | packages the experience (the web shell: workers/interactive_web/app_shell) and publishes it to the proposal origin |
wrk-mgr · blender | wrk-mgr | converts .blend/.fbx to compressed glTF, audits scenes, converts avatars |
| src-mgr | src-mgr | syncs the Drive sources and their labels |
Keys for the team (not announced to the client): Ctrl+Shift+K or ?tune opens the tuning panel (gallery lights, captions, presenter animations, video card, render resolution); changes apply at once and Save fixes them for the unit on the server. Ctrl+Shift+V switches the video presenter on or off for the unit.
Reference documentation in the repositories: wrk-mgr/docs/proposal-scene-spec.md (this specification), wrk-mgr/docs/workers/interactive-proposal.md (the shell and its runtime contract), flow-mgr/docs/proposals.md and flow-mgr/docs/live-relay.md (publishing, audit, voice, forms). Shell changes deploy as the interactive_web Modal worker and reach each unit when it is republished.
10. The scene configuration file
One file per unit, in TOML, in the unit's Drive sources, whose name contains scene config or configuración de la escena (case and accents ignored). It is read at publish and on every /gen-proposal CODE --showcase. It holds three things: the exercise's settings (the same ones in the tuning panel), one table per scene object under its exact Blender name, and the guide's instructions. The former "scene topics" document no longer exists.
How it combines with the panel (Ctrl+Shift+K): the file is the baseline; whatever is saved in the panel sits on top, per unit. A long value (an instruction) is edited with the … button in a large box. The object tables appear in the panel as the Scene objects group and can be corrected and saved there too.
[quiz]
perStation = 2
passMark = 0.7
[tasks]
[prompts.rubric]
text = "..."
[scene]
welcome = "Bienvenido a la línea de inspección."
[Station_01_Placa]
task = "Revisa la placa: estencilado, medidas y espesor"
topic = "Qué se verifica en la placa y por qué importa"
description = "The plate table at the mill entrance: the plate on the rollers, the 0-1\" micrometer, the tapes and the F-TUAC-022 report on its clipboard"
questions = [["¿Qué datos del estencilado verificas?", "colada, proveedor y grado"], ["¿Con qué mides el espesor?", "con el micrómetro"]]
[Hotspot_Micrometer]
action = "Mide el espesor de la placa con el micrómetro"
reading = "12.50 mm"
[Clipboard_Inspeccion]
instructions = "Captura la colada y el espesor medido"
[Clipboard_Inspeccion.expected]
Espesor = "12.50"
[Show_Balde_De_Pintura]
note = "Pintura de marcado para identificar la placa aprobada"
10.1 Settings
One table per panel group; the keys are the panel's, nested as tables or dotted (card.radius = "14px"). Default in parentheses.
[render] — Render resolution
| Key | Default | What it does |
|---|---|---|
maxPixelRatio | 2 | Device pixels per CSS pixel in the gallery (cap). |
walkMaxPixelRatio | 1 | The same cap inside the scene; 0.5 doubles the frame rate at the cost of sharpness. |
powerPreference | "high-performance" | Asks a two-GPU laptop for the discrete one (applies on reload). |
[video] — Presenter video (Kira)
| Key | Default | What it does |
|---|---|---|
layout.widthShare | 0.17 | Card width as a share of the window. |
layout.minWidth | 132 | Minimum width in px. |
layout.maxWidth | 288 | Maximum width in px. |
layout.aspect | 0.76 | Width/height ratio of the card. |
layout.margin | 16 | Margin to the edge, px. |
layout.zoom | 1 | Scale of the video inside the card. |
layout.focusY | 0 | Vertical framing point, 0–100 (0 = head at the top). |
fade.hold | 3 | Seconds the card stays after she speaks. |
fade.fadeIn | 0.35 | Fade-in seconds. |
fade.fadeOut | 0.6 | Fade-out seconds. |
servo.intervalMs | 30 | How often playback is corrected, ms. |
servo.onset.minLag / cushion | 0.5 / 0.3 | At speech onset: the minimum lag before a snap to the live edge, and the cushion it snaps to, s. |
servo.speaking.minLag / cushion / fromMs / untilMs | 0.6 / 0.3 / 40 / 200 | While speaking: one snap allowed between fromMs and untilMs after onset. |
servo.idle.minLag / cushion | 1.5 / 0.3 | When idle: the leash that keeps the video from falling behind. |
trim.after / behind / keep | 25 / 20 / 15 | Buffer trimming: every how many seconds, how far behind, how much to keep. |
codecs.native / baseline | avc1.42c01f… / avc1.42E01E… | MIME types of the stream (leave alone). |
card.radius | "0px" | Corner radius of the card (CSS). |
card.edge | "1px solid var(--tb-line)" | Card border (CSS). |
[caption] — Captions
| Key | Default | What it does |
|---|---|---|
holdAfterTurnMs | 2500 | Ms the caption stays after her turn, inside the scene. |
maxChars | 360 | Characters shown (cut at a sentence start). |
markdown | true | Render the model's bold as bold. |
maxAgeMs | 20000 | Inside the scene the caption also clears this long after its last words, even if the turn never closed. |
strayTokens | ["stdin"] | Stray model tokens removed from the caption. |
strayPatterns | ["response:…"] | Regular expressions for what the model leaks into its words and must never be captioned (e.g. a tool result). |
[presenter] — 3D presenter animations (Camila)
| Key | Default | What it does |
|---|---|---|
idle / talk / talkAlternate | "" | Clip names to use; empty = the model's. |
swapSeconds | 9 | Seconds between alternating talk clips. |
crossfade.talkSwap / toTalk / toIdle / fadeOut | 0.6 / 0.35 / 0.45 / 0.6 | Crossfade seconds between clips. |
clips | "" | Fixed clip list (e.g. "Idle"). |
[lighting] — Gallery lighting
| Key | Default | What it does |
|---|---|---|
toneExposure | 0.85 | ACES exposure. |
envIntensity | 0.9 | Image-based lighting strength. |
key.intensity / key.position | 2.0 / [3, 6, 4] | Main key light. |
fill.intensity / fill.position / fill.color | 0.45 / [-4, 2.5, 5] / 0xbfd0e0 | Fill light. |
hemi.intensity / hemi.sky / hemi.ground | 1.0 / 0xdde7df / 0x37352f | Sky/ground ambient. |
rim.intensity / distance / decay / position | 8 / 24 / 2 / [0, 3.4, -4] | Rim light. |
[face] — 3D presenter face
| Key | Default | What it does |
|---|---|---|
roles.* | nombres de morph | Which model morph plays each role (jaw, open, wide, smileL…). |
visemes.* | pesos | Morph mix per viseme (AA, EE, IH…). Advanced. |
[guide] — Guide inside the scene
| Key | Default | What it does |
|---|---|---|
gazeSilent | true | On a tour, gaze is silent context, not a cue to speak. |
turnStallMs | 12000 | Her turn with no audio for this long = closed (stalled model). |
lessonStallMs | 45000 | The same while she teaches a lesson (the model pauses longer between its parts). |
resumeAfterMs | 3000 | If a lesson is interrupted and no words of the client are heard within this time, it was a noise: the guide resumes the lesson from the slide on screen. |
describeForms | false | When a sheet opens, the guide explains it aloud (the clipboardOpen instruction). Off, she only learns silently which sheet was opened and can answer about it. While she speaks nothing can be walked to or worked (turning and looking around still work), but a sheet always opens, and nothing is held during a conversation with a character. |
clickSkipsLesson | true | While she speaks, a click on another station's marker (in VR, the trigger pointed at the marker) quiets her and goes there. If she was teaching a lesson, the station left stays untaught and not done: the trainee has to come back, and the lesson starts over then; work on it from a distance does not count until they do. While she asks a check question, and in the exam, the click waits. Off, the click always waits for her to finish. |
[gaze] — Visitor gaze (the tour only: the task exercise never uses gaze)
| Key | Default | What it does |
|---|---|---|
enabled | true | Measure where the visitor looks, on a tour. |
tickSeconds | 0.5 | How often it is measured. |
coneDegrees | 8 | Gaze cone. |
minDistance / maxDistance | 2.5 / 12 | Valid distances, m. |
dwellSeconds | 5 | Seconds still on something to count. |
stillMove / stillTurnDegrees | 0.15 / 4 | What counts as still (m, degrees per tick). |
[tasks] — Task exercise
| Key | Default | What it does |
|---|---|---|
enabled | true | Off = narrated tour, no checklist. |
requireInteractions | true | A task requires arriving and doing everything at the station; off = arrival alone. |
stuckSeconds | 60 | No progress for this long = a one-line check-in (once per task). |
checkEveryMs | 5000 | How often the stuck clock is checked. |
maxTextChars | 160 | Maximum length of a task's text. |
summaryValuesChars | 300 | Characters of form answers quoted to the guide. |
startScreen | true | Start screen when the exercise begins: the welcome line, the tasks in order and the controls; the guide waits until it closes. |
startScreenSeconds | 180 | It closes by itself after this long (or on a click anywhere). |
startLoadMaxS | 20 | How long at most the start screen waits for the material (the infographics) to preload before showing "Click anywhere to begin". |
startMusic | "industrial" | The music while it is open: industrial (the default) or office (corporate); none = no music. |
startMusicVolume | 0.5 | Its volume, 0–1. |
startMusicFadeS | 1 | Fade-out seconds when it closes. |
[quiz] — Assessment: checks and exam
| Key | Default | What it does |
|---|---|---|
enabled | true | Questions after each task. |
perStation | 2 | Questions per station when the file gives no questions. |
exam | true | Final exam: the stations marked exam = true again, alone, in order. With none marked there is no exam: the checks give the final score. |
passMark | 0.7 | Minimum (0–1) to pass a check and the exam. |
checksCount | true | The checks' average must reach passMark too for the exam to pass; off, the practical alone decides. |
nudgeSeconds | 45 | No grade for this long = one reminder to the guide. |
answerSeconds | 180 | No answer for this long = the question scores 0 and the check moves on. |
clockTickMs | 5000 | How often the exam's minutes are refreshed (and the caption's age checked). |
music | true | Success or failure music while the report is open; the report (and its music) opens once the guide has finished her closing words, not over them. |
musicVolume | 0.5 | Its volume, 0–1. |
musicFadeS | 2 | Fade-out seconds when the report closes, on restart or on exit. |
musicDuck | 0.25 | While the guide speaks, any music (the start screen's, the outcome's) drops to this fraction of its volume and comes back after. |
musicDuckS | 0.4 | Seconds of that drop and of the return. |
musicSuccess | "assets/music/exam-success.mp3" | The success track (path relative to the unit's page; empty = a synthesized phrase). |
musicFailure | "assets/music/exam-failure.mp3" | The failure track (same). |
[sound] — Sound
| Key | Default | What it does |
|---|---|---|
muteKey | "KeyX" | Key that mutes or unmutes all sound (her voice and the music), like the dialog's speaker icon; inactive while typing. |
[mic] — Microphone while she speaks
| Key | Default | What it does |
|---|---|---|
level | 0.025 | Output level that counts as her voice. |
tailMs | 400 | Ms the mic stays closed after her voice. |
wholeTurn | true | Closed for her whole turn, not only while sound plays. |
turnMaxMs | 90000 | Cap on that, in case a turn never ends. |
[listen] — Microphone: when she listens
| Key | Default | What it does |
|---|---|---|
windows | true | Inside the scene the mic opens only when she listens. |
windowMs | 8000 | Window open after each of her turns. |
heardExtendMs | 6000 | Extension while the relay hears speech. |
holdKey | "KeyM" | Key that opens the mic while held. |
vrHoldButton | 4 | In the VR headset, the controller button that opens the mic while held (WebXR standard gamepad index: 4 = A on the right hand, X on the left). |
vrCheckOpen | true | In the VR headset, while a check question waits for its answer, she listens between her turns (there is nowhere to type); her own turn stays closed. |
[show] — Glow of the objects she names
| Key | Default | What it does |
|---|---|---|
eachS | 2 | Seconds each named object glows. |
videoLeadMs | 1200 | With the video presenter: wait before lighting (text arrives before the voice). |
[markers] — Markers
| Key | Default | What it does |
|---|---|---|
riseRatio | 0.6 | How high a station's marker floats over eye level, as a fraction of the visitor's stature (0.2 left it across the shelves and in front of the hotspots). |
hotspotRiseRatio | 0.2 | The same for a hotspot's icon, measured over the floor plus the stature. |
ceilingMarginRatio | 0.1 | Under a ceiling, markers stay this fraction of the stature below it. |
[actpip] — Action close-up
| Key | Default | What it does |
|---|---|---|
enabled | true | Show the inset during an action. |
widthShare / minWidth / maxWidth / aspect / margin | 0.3 / 220 / 520 / 1.5 / 16 | Size and placement of the inset. |
frame | "equipment" | equipment frames what Play_ animates; body frames the character. |
equipmentFill / equipmentMinDistance / equipmentSide / equipmentAbove | 0.6 / 0.35 / 0.6 / 0.45 | Instrument framing: fill, minimum distance, swing toward the character's right, elevation. |
side / above / lookHeight / reach / fov | 1.9 / 0.2 / 0.7 / 0.45 / 38 | Character framing (body mode): side offset, elevation, look height, forward offset, field of view. |
[nav] — Navigation (paths)
| Key | Default | What it does |
|---|---|---|
enabled | true | With a Navmesh in the scene, a click on a station or a point walks a path around the Collider_ objects; off (or no Navmesh) = a straight line. |
cellM | 0.25 | Cell size of the grid over the Navmesh, m. |
maxStepM | 0.35 | What rises less than this above the floor is a step, not a wall. |
headroomM | 1.7 | The visitor's height: anything lower in the cell blocks it. |
radiusM | 0.35 | The visitor's half-width: blocked cells grow by it. |
margin | 2 | Metres of grid beyond the Navmesh's footprint. |
budgetMs | 6 | Milliseconds per frame spent building the grid on entry. |
maxCells | 200000 | A larger Navmesh gets coarser cells. |
speedMps | 2.2 | Walking speed along the path, m/s. |
minHopS / maxHopS | 0.5 / 8 | Shortest and longest hop, s. |
snapM | 1.5 | How far an endpoint may move onto a walkable cell, m. |
navmeshPrefix | "Navmesh" | Prefix of the Blender object with the walkable surface (see the scene spec). |
[characters] — Characters: action paths
For characters with a path (see [Character_Name] in 10.2).
| Key | Default | What it does | ||||||
|---|---|---|---|---|---|---|---|---|
walkSpeed | 1.2 | How fast a character walks its path, m/s. | ||||||
walkClipSpeed | 1.4 | The pace the walk animation is authored at; it plays at walkSpeed / walkClipSpeed so the feet do not slide. | ||||||
turnSpeed | 4 | Radians per second it turns (toward the way ahead, the chair, the visitor). | ||||||
fadeS | 0.35 | Seconds one animation blends into the next. | ||||||
occupyM | 0.6 | A character within this of a station's spot is still on it, m. | ||||||
besideM | 0.8 | When the character has not cleared the station the visitor chose, the visitor stops this far to one side, m. | ||||||
occupied | "leave" | What a station that does not say occupied means: "leave" or "inactive". | ||||||
sitDown / seated / standUp | "Sentarse" / "Trabajar" / "Levantarse" | Names of the sit-down, seated-work (looping) and stand-up animations; found like an act's. | ||||||
lowerBody | `"Hip\ | Pelvis\ | Thigh\ | Calf\ | Knee\ | Foot\ | Toe"` | Bones (a pattern on their names) that stay with the chair while a seated character talks; the talk animation moves the rest. |
walkSrc / walkClip | /avatar-assets/shared/cc-animations-meshopt.glb / "Avatar_Walk" | The shared walk (a man's). | ||||||
walkFemaleSrc / walkFemaleClip | /avatar-assets/shared/cc-walk-female-meshopt.glb / "Walk_F" | The shared walk of a character whose gender is female. A walk delivered with the character wins over both. |
[lessons] — Station lessons
At publish the system writes one lesson per station from the proposal's material and the scene configuration: title, objective, every key point and step the material gives (no cap), safety, the check questions with their answers, and a board of slides (up to slides): each slide has a title, a few labels carrying the figures and an infographic generated with the image provider and model of [lessons]. Every infographic of the unit gets the same reference images: the client's material images (its documents' figures and its photos), in their order, up to referenceImages; when the material has no images none are sent and the infographic is drawn from its description. The guide teaches the whole lesson on arrival, slide by slide, naming each one ("Slide 2: …"); when she names one, its infographic appears alone on screen (no frame, title or controls), stays showSeconds or until she names another, and fades out; the checklist's Lesson button has her teach it all again from the start (it does not mark, complete or check it again; choosing another station meanwhile only quiets her). Without infographics (drawing them is off by default: each one is paid) there is no board and the lesson never mentions slides: the guide teaches the same parts, one per turn, each by its topic. The microphone is closed for the whole lesson: nothing interrupts it until it ends. The check questions come from that same lesson (unless the station's table carries questions). The lesson is rewritten only when the material, the configuration or the scene changes. An infographic is drawn only when its slide has none, or when the publish command names it with --redraw: never by itself, not because the slide's text, the style, the provider or the model changed (every image is paid for).
| Key | Default | What it does |
|---|---|---|
enabled | true | Write a lesson per station at publish. |
images | false | Draw the infographics the slides still lack. Off unless turned on here (each image is paid). Pictures already drawn are always kept and shown; --redraw redraws what it names even when off. |
words | 150 | Words at most in the lesson text (the scripts of all slides together), about the station only; the questions come from that text alone. |
slides | 4 | Slides per station at most. |
imageProvider | "openai" | Image provider for the infographics (openai, gemini, bfl). |
imageModel | "gpt-image-2.5-sunburst" | That provider's model for the infographics. |
referenceImages | 4 | How many images of the material go as references with each infographic (the same for all). |
questions | 2 | Check questions per lesson; the written bank holds questionBank times this many and the page picks [quiz] perStation of them at random on each check (a replay does not repeat the questions). |
questionBank | 2 | How many times questions the lesson's question bank holds. Each question tests one concrete fact of the scripts (a value, tolerance, tool, document, criterion, step order); the lesson may write fewer than the bank rather than pad, and questions that answer themselves, that the station's name answers, or that another station already asks are dropped. |
sourceChars | 60000 | How much of the material each lesson sees. |
board | true | Show the lesson's infographics on screen. |
autoOpen | true | Arm them by itself on reaching the station (they appear when the guide names them). |
showSeconds | 120 | Seconds an infographic stays on screen unless the guide names another. |
fadeMs | 600 | Milliseconds of the fade in and out (on a change the old picture fades out before the new one fades in). |
holdAfterTurnS | 8 | Seconds the last infographic stays on screen after the guide finishes the lesson. |
preloadParallel | 2 | How many infographics download at once on entry (all at once left the intro music waiting). |
turnPerSlide | true | The lesson goes one slide per turn: the page sends slide 1, when that turn ends slide 2, and so on; each infographic appears as its own turn's audio starts. Off, the whole lesson goes in one turn (the model cuts it at ~170 s of audio). |
cueWords | ["lámina", "lamina", "slide"] | Words with which the guide names a slide and its number so the board turns. |
[telemetry] — Telemetry
| Key | Default | What it does |
|---|---|---|
enabled | true | The page sends its log (decisions, errors, settings, marks) to the session's log on the server. |
perf | true | Also times every frame (CPU per section, GPU, slow frames, long tasks); turn off when not measuring. |
flushMs | 2000 | How often a batch goes. |
maxBatch | 60 | Entries per batch. |
maxBuffer | 600 | Entries kept while disconnected (oldest dropped). |
maxChars | 500 | A message's maximum length. |
errorsPerMinute | 20 | Console errors kept per minute. |
markKey | "KeyL" | Ctrl+Shift+this key copies the session id and marks the moment in the log. |
longTaskMs | 50 | The browser's long-task threshold (informational). |
[prompts] — Instructions to the guide
Each key is a table with es and en (the instruction in each language); {n} is a number the page fills in. rubric and protocolExtra carry text only.
| Key | Moment |
|---|---|
enterTour | welcome to the tour (no tasks) |
enterExercise | welcome to the task exercise |
enterStation | welcome when the client spawns on the first task's station: greets and teaches it ({n} = sentences) |
vr | welcome into the VR headset |
ar | the model in augmented reality |
arExercise | the character practice in AR |
station | arrival at a station (tour) |
stationReached | arrival at a task's station with no written lesson: improvises one ({n} = sentences) |
stationLesson | arrival at a task's station with a written lesson: teaches it in full |
lessonResume | a lesson interrupted by a noise: picks it up where it left off |
lessonSkipped | another station was chosen during a lesson: she stops, the station stays untaught and is taught again on return; only with [guide] clickSkipsLesson |
enterLessonSlide | welcome on the first task's station with turnPerSlide: a one-sentence greeting and slide 1 only |
lessonSlideFirst | arrival at a station with a lesson and turnPerSlide: slide 1 only |
lessonSlideNext | every following slide of the lesson (and the current one again after a noise interruption) |
lessonSlideResume | the current slide, picked up where a typed question cut it off |
typedQuestion | what the client types in the dialog: a short answer, no question at the end. While a check question waits for its answer, what is typed in the dialog is the answer (as in the question's card) and goes as written, without this instruction |
enterLesson | welcome when the client spawns on the first task's station and it has a written lesson |
taskDone | task done, ask for the next |
lastTaskDone | last task done, closing (no exam) |
checkOpen | open the check: confirm and ask question 1 ({n} = questions) |
checkNext | next question, after teaching the previous answer |
checkDoneNext | check finished, next task |
checkDoneLast | last check finished with some question missed: final result and the study plan the page builds from the slides (per missed question: the slide that teaches it, quoted, and what to do in the scene); she says it point by point |
checkDoneLastClean | last check finished with no question missed: final result and a congratulation, no study plan |
checkStuck | reminder: grade or repeat |
examStart | exam announcement |
examDone | closing with the exam result and the page's study plan, when some question was missed |
examDoneClean | closing with the exam result and no study plan: no question missed |
checkIn | check-in after inactivity |
act | what the client is doing at a point |
actDone | action finished |
showClick | describe an object on click |
clipboardOpen | sheet opened: teaches it in depth (what for, each field and where its data comes from, what happens to it); only with [guide] describeForms |
formUnfilled | sheet closed empty |
comment | brief comment (other events) |
talkDebrief | feedback after a character conversation |
awareness | prefix of silent contexts |
rubric | text: the grading rubric |
protocolExtra | text: an addition to the guide's protocol |
[controls] — Control panel: keys and functions
| Key | Default | What it does |
|---|---|---|
functionDoneS | 1 | Seconds a machine function must stay active to count as done. |
keyDeflectPerS | 3 | How fast a stick worked by keys reaches full deflection (per second). |
keyReturnPerS | 4 | How fast it springs back when the keys are let go (unless sticky). |
knobKeyPerS | 0.5 | Share of a knob's range its held key turns per second; a knob with steps moves one position per press. |
10.2 Scene objects
One table per object, under the exact Blender object name ([Station_01_Placa], [Hotspot_Micrometer], ["Show_Balde_De_Pintura"]): that is how they match. The keys depend on the prefix. A name with accents or spaces is written as it is, with or without quotes ([Show_Tapones_Para_Oídos], [Station_03_Mesa de herramientas]).
[Station_NN_Name / Seat_Name]
| Key | What it does |
|---|---|
task | the station's task: what the checklist shows and what she asks for |
topic | the topic she teaches on arrival |
description | the station itself in 2-3 sentences: the place, the equipment, instruments and documents there and what the learner sees; it is the setting of every slide of the lesson and she says it on arrival. Without it the scene's facts are used (the station's number and name, the objects that stand at it and its Blender note); a model never invents one. |
questions | list of ["question", "expected answer"] pairs; with it she asks exactly those, in order |
images | true or false: false leaves the station with no infographics (not even drawn ones); true draws the ones it lacks even when [lessons] images is off; without the key [lessons] images rules |
exam | true or false (default false): the station is part of the final exam; with no station set to true there is no exam and the checks give the score |
occupied | "leave" or "inactive" (default [characters] occupied, "leave"): what happens when the visitor chooses the station while a character is on it. "leave": the character moves on (stands up if seated and goes on from its next walk); if it has not cleared the spot when the visitor arrives, the visitor stops to one side and it still counts as arriving. "inactive": while the character is there the station cannot be used: its marker is grey and takes no click, and walking up to it does not count (no lesson, no task) until the character leaves on its own path. |
[Character_Name]
| Key | What it does |
|---|---|
note | what she says about the character when it is named or talked to |
path | its action path: steps it repeats in order while the visitor is inside the scene (below) |
[Character_Alejandra]
path = [
{ act = "Saludar" }, # an animation, once
{ walk = "Archivo" }, # walk to that station along the Navmesh
{ act = "Buscar" },
{ walk = "Escritorio" },
{ sit = true }, # sit, facing the way the station's empty faces
{ work = [20, 60] }, # hold what it is doing (seated work, or idle standing) 20 to 60 s
{ stand = true }, # get up
]
- Places are stations:
walknames a station by its name (ArchivoisStation_03_Archivo; case and accents do not matter). A station only characters use is an ordinary station no exercise lists in itstask_stations([module..exercise.], in the player's documentation). act = "Name"looks for the animation in this order: one delivered for that character, the scene'sAct_Name, and the one imported for everyone withscripts/character_clips.py import --act Name --url …. Sitting down, seated work and standing up are animations by those names ([characters] sitDown / seated / standUp). Walking: one delivered with the character, or the shared one (the woman's when itsGenderis female).- The path starts when the visitor enters the scene and starts over on each entry; in the gallery and in the augmented-reality exercise the character stays still on its idle.
- A conversation pauses it: walking, it stops and turns to the visitor; seated, it talks from the chair. When the conversation ends it carries on from the same step. Walking up and pressing E never makes it leave.
- A station the visitor is at, or heading to, is taken: a character whose next
walkgoes there waits where it is until the visitor leaves. The other way round is the station'soccupied(above). - Without a
Navmeshit walks straight. Characters do not steer around each other or the visitor.
[Hotspot_Name]
| Key | What it does |
|---|---|
action | what the client does when working it (said at the start) |
reading | the instrument's reading; said when the action completes |
note | anything else to say on completion |
[Clipboard_Name]
| Key | What it does |
|---|---|
instructions | what she says when the sheet opens |
expected | table of field = expected value, for her to judge the sheet |
[Show_ / Screen_ / Button_ / Knob_ / Joystick_]
| Key | What it does |
|---|---|
note | what she says about the object when named or clicked |
keys | controls only: the keys that work it on a computer. A joystick takes four (up, left, down, right: "ijkl"), a knob two (down, up: "zx"), a button one ("p"). They work only at the control's station with no card open; the arrows, E, V and the space bar belong to the scene and cannot be used. |
label | controls only: the short name the remote prints beside the control ("S1", "B2.RL"). The viewer shows it floating beside the control, with a line to it (see "The panel's close-up and labels" below). A control without a label gets none. |
[scene]
| Key | What it does |
|---|---|
welcome | her first sentence on entry, as written |
The tables only the training player uses ([module.*], title in [scene]) and the /gen-player findings are in the player's documentation.
Without a table for an object, the page uses the object's Blender note property if present, else its name. Everything in a table also reaches the guide as text, so she can answer questions about it.
Machine functions: [conditions] and [functions.Name]
On a real machine, what the machine does comes from several controls at once: both sticks up drives the tracks; the right stick's button held with the stick forward moves the arm; the regulator sets the hammer's power. Each control moves its own Play_ action (the control itself, the operator's hand); what the machine does is described here, one table per function.
[conditions]
ready = ["Button_S0 off", "Button_S1 on"]
[functions.Drive_forward]
label = "Drive forward on the tracks"
when = ["ready", "Joystick_Turret.y > 0.2", "Joystick_Boom.y > 0.2"]
plays = "Play_Tracks_Machine"
follows = "Joystick_Turret.y"
[functions.Regulated_hammer]
label = "Hammer at regulated power"
when = ["ready", "Button_Hammer held", "Knob_R1 > 0"]
plays = "Play_Hammer_Machine"
speed_from = "Knob_R1"
[functions.Drive_both_tracks]
label = "Drive forward on both tracks"
when = ["ready", "Knob_S5.step = 0", "Button_B1LR held", "Button_B2RL held"]
plays = ["Play_Track_Left_Machine", "Play_Track_Right_Machine"]
drive = 1
Conditions (in when and in [conditions]): the name of a [conditions] set, or a control with its test:
| Condition | Holds when |
|---|---|
Button_X on / Button_X off | the button is on (mode = toggle) or held; or not |
Button_X held | the button is held down (mode = hold) |
Button_X | on or held |
Knob_X > 0.5 | the knob is past halfway (0 = minimum, 1 = maximum) |
Knob_X.step = 2 | the knob with steps is at position 2 (0 = the first): a selector |
Joystick_X.y > 0.2 | the stick pushed forward (.y: −1 back, 1 forward; .x: −1 left, 1 right) |
Comparisons: >, <, >=, <=, =. not in front negates a control condition. The function is active while all hold. Control names are written as in Blender, without spaces.
| Key | What it does |
|---|---|
when | list of conditions (required) |
plays | the machine's Play_ action it moves, or a list of actions moved together (both tracks): ["Play_Track_Left_Machine", "Play_Track_Right_Machine"] (required) |
follows | a stick axis (Joystick_X.y) or knob: the action runs at that value × speed per second, backwards when negative; half-pushed, at half speed |
drive | without follows or mode: a number from −1 to 1 (not 0); while the function is active the action runs at that value × speed per second, backwards when negative. It is a function a button moves: on the Brokk, with S5 up, B1.LR drives both tracks forward (drive = 1) and B1.LL back (drive = -1). An action keeps one position, whether a stick or a button moves it |
speed | share of the action per second at full push (default the Joystick_'s: 0.5) |
speed_from | a knob or stick axis that scales the speed (the regulator). While it is at zero the function moves nothing and does not count as done. |
mode | without follows: loop (default) repeats the action while active; once plays it each time it becomes active; hold runs it forward while active and back after |
rest | where along the action the machine stands at rest, from 0 (start) to 1 (end). Default: the middle when a stick or a drive moves it (it goes both ways, like the stick's own actions), else the start |
travel | true, with follows or drive: the action carries the whole machine (it moves only the root of its rig, as the Brokk's tracks do) and the machine goes as far as it is driven, from wherever it stands, instead of stopping at the action's end. A wall or other solid stops it, or a person (the visitor or a character) within 45 cm. The Collider_ round the machine's root travels with it and is its footprint; restarting the exercise puts the machine back |
label | the function's name in the task list and to the guide |
note | what the guide knows about it |
station | the station it belongs to (default: the station of the first control in when). Several stations at one place (within 25 cm) are several tasks done there in order without walking; a fixed control's keys (a plug) work at the station of its place and at those whose functions or states read it |
Each function is an item of its station's task: done once it stays active for [controls] functionDoneS seconds. At a station with functions, the controls are no longer items of their own nor news to the guide: the task is what the machine does. The controls' actions should move only the control (and the operator's hand); the machine's movement goes in the actions the functions name.
Function actions add up. As the scene loads, the viewer stands the machine at each action's rest pose (rest), and each active function adds how far its action moves away from that pose. That way both sticks at once move the boom and the arm fully, even though Blender exports every bone of the arm in each action and the hoses move in several actions. Played whole, each action would hold at rest what the other moves, and the viewer would average them to half. The same goes for a stick's two axes, which add up from the centre.
Machine states ([states.Name]): what the machine remembers, such as the control unit switched on, the motor running or the control circuit made.
[states.on]
label = "Switch the control unit on"
set = ["Button_S1 held"]
clear = ["Button_S0 on"]
[states.circuit]
label = "Make the control circuit"
set = ["on", "Button_Reach held"]
clear = ["not on"]
idle_s = 3
A state turns on while all its set conditions hold and off while all its clear conditions hold (when both hold, it turns off). With idle_s it turns off by itself after that many seconds with no function active: the Brokk's circuit drops after 3 s and the stick's button makes it again. With hold_s it turns on only once its set conditions have held that many seconds without a break: the Brokk's main switch Q1, 3 s at 0 before the other phase. With while it can only be on while all those conditions hold: the motor, while the unit is on and the machine has power (clear needs all its conditions at once, so it could not stop it on either one). With last = true, a state with a label is listed after the functions: disconnecting comes last. With initial = true it starts on. A condition names a state the way it names a [conditions] set (on, not circuit). A state with a label is also a task item: it counts the first time it turns on and comes before the functions in the list, because the start-up comes first. It also takes note and station.
Indicators ([indicators.Name]): a light on the model, the mesh Indicator_Name (or another that node names). Each colour (green, yellow, red, orange, blue, white) lists the conditions that light it; the first that holds wins, and when none holds the light keeps its own material.
[indicators.LED2]
green = ["circuit"]
yellow = ["on", "not circuit"]
A display shows words while it is lit: its text table pairs a condition (a state, a [conditions] set, or a control's condition, quoted) with what the display says at that moment. The first that holds wins; when none holds, the display only glows. \n separates the lines. The words are drawn as a backlit screen, the lit colour behind and the letters dark. The mesh needs a full UV (the image fills the display) with the top of the display at the top and its left at the left, as its user sees it; a mirrored UV shows the words backwards.
[indicators.Display]
green = ["on"]
[indicators.Display.text]
motor = "+23°C 20 bar\n102 h"
on = "BROKK\nStart Engine"
Instead of words, a text entry may be a screen laid out like the machine's own, as an inline table:
[indicators.Display.text]
motor = { lines = ["+23°C 20 Bar", "102 h"], left = "battery 4/4", right = "signal 4/4", mark = "lubrication" }
on = { logo = "BROKK", lines = ["START ENGINE", "(I) (M)"] }
| Key | What it draws |
|---|---|
logo | a word set large, bold and underlined at the top (the brand) |
lines | the lines, centred below |
left / right | a bar gauge along that edge with its symbol at the foot: "symbol level/of" (on the Brokk, the battery and the radio signal, 0 to 4 bars) |
top | a horizontal gauge along the top, its symbol at the start (the oil level, say) |
mark | a symbol after the last line (the hammer's lubrication, say) |
Symbols: battery, signal, oil, lubrication, service. Everything is drawn in the dark ink on the lit colour. The page draws the screen itself: no image is needed.
An indicator also takes note (what the guide knows about it) and label, its short name ("LED2"), shown beside it as a control's is. The machine's own lights (its work lamps) are indicators too: an Indicator_Lights mesh lit white with the motor.
The panel's close-up and labels
While the visitor works a panel (they are at its controls' station and no card is open):
- In third person a close-up of the panel appears in the bottom left corner, seen from the operator's eyes with the far edge up, as first person sees it. The shoulder camera cannot see a remote hanging from the belt, because the body is in front of it. The person is not drawn in that inset, because its camera sits between their eyes and the panel. The controls fill most of the inset: they are framed by their own boxes, centred, with room for the labels. Nothing between the camera and the panel hides it (a beam, say). While an
Act_animation plays, its own close-up comes first. In a VR headset there is no inset. - In first person, looking down at a remote the visitor wears (on the belt), the view moves over the remote's middle and backs off just enough for all of it to fit the open part of the screen. It stays whole while the body sways standing still. Looking up again, the camera is back at the eyes.
- Labels: each control or indicator with a
labelhas its name floating beside it, with a line to it: in the third-person close-up and over the first-person view. A label goes on the side facing away from the panel when that side is free, else the next free side, clear of other controls and labels. With no free side it takes the one that costs least: a line crossing another costs more than covering part of a control, because it reads as the other's label. Two labels whose lines still cross swap places. It keeps its side while that stays free, so it does not jump as the view sways. - A remote the visitor wears is its station's panel even when the station also has controls fixed in the scene (the machine's main switch, a plug): those are worked where they stand, and the close-up, its labels and the first-person framing are the remote's.
- The panel is what holds all its controls and indicators: their nearest common parent in the model (on the Brokk, the remote's
Controlbone) plus the meshes skinned to that parent alone (the remote's housing). When their common parent is the whole avatar or the whole scene, the inset frames the controls alone.
10.3 Findings at publish
| Finding | Meaning |
|---|---|
scene_config_missing | no configuration file among the sources |
scene_config_invalid_toml | the file is not valid TOML (ignored whole) |
scene_config_unknown_object | a table whose name is neither a settings group nor an object with a known prefix |
scene_config_unknown_key | a key that table type does not accept |
scene_config_bad_value | a value of the wrong type |
scene_config_stray_value | a loose value outside any table |
scene_config_bad_path_step | a path step that is not act, walk, sit, work or stand |
scene_config_bad_condition | a when or [conditions] condition that does not follow the condition table's form (the function is ignored) |
character_path_unknown_station | a walk names a station the scene does not have |
character_path_act_no_clip | an act with no animation (none delivered, no Act_ in the scene, none imported) |
character_path_no_sit_clips | a sit without the sitting animations: the character stays standing |
character_path_no_navmesh | a path with walk in a scene with no Navmesh: it walks straight, through whatever is in the way |
character_path_no_character | a [Character_…] with a path but no character delivered |