Português

Documentação xr/studio

API de Custom Code

Programe a sua história com a ação Custom Code: o namespace cyango, os seus métodos e tipos, ler inputs GUI, variáveis, navegação e exemplos.

Custom Code

A ação Custom Code corre TypeScript quando o seu evento dispara, como On Click, On Scene Ready ou On Language Changed. Use-a quando os tipos de ação incorporados não chegam, por exemplo para ler inputs de formulário, ramificar por dispositivo ou idioma, guardar valores entre cenas ou controlar a história diretamente.

Para adicionar, abra o separador Actions numa entidade (ou selecione a cena), escolha um event type e adicione uma ação Custom Code. O editor tem autocomplete TypeScript — escreva cyango. para ver o que está disponível.

Quando guarda a história, o Studio compila cada bloco de código personalizado para JavaScript. O player executa apenas o output compilado, por isso obtém edição com tipos sem enviar o compilador TypeScript aos visitantes. Corrija erros de compilação mostrados no editor antes de publicar.

A sandbox

O seu código corre dentro de uma sandbox segura, envolvida numa função async. Na prática:

  • Pode usar await diretamente, e return para parar mais cedo.
  • console.log, setTimeout, setInterval (limitado a 60 segundos) e fetch estão disponíveis.
  • Os globais do DOM estão bloqueados: window, document, location, navigator, history, eval. Use cyango.utils.getWindowLocation() e cyango.utils.getNavigator() em vez disso.
  • Os erros são apanhados e registados na consola do browser, por isso um trecho com erro não vai quebrar a história.

Tudo o que o Cyango expõe vive num único objeto global, cyango.

Uma história tem também dois blocos que correm uma vez, quando a história carrega. Abra Settings e depois Head and Footer Code. O Head corre primeiro e o Footer corre no fim. Ambos usam o mesmo editor e a mesma sandbox de uma ação Custom Code, com os seus próprios snippets no painel ao lado do código.

Use-os para preparar a história antes de o visitante a ver, ou para reportar sobre ela depois:

  • Defina o idioma ou o nível de qualidade a partir do URL, antes de a primeira cena ser mostrada.
  • Carregue uma configuração do seu backend para variáveis que qualquer ação pode ler.
  • Instale o Google Analytics, o Google Tag Manager ou qualquer outra tag.
  • Escreva as tags de SEO e de partilha: canonical, robots, Open Graph, Twitter cards e JSON-LD.

O objeto head

Estes dois blocos têm uma coisa que mais nenhum bloco tem: head, que escreve na página. O document e o window continuam bloqueados em todo o lado, por isso é assim que uma tag chega à página.

MétodoO que faz
head.addScript(src, options)Carrega um script externo, uma só vez. Use await quando a tag tem de ser configurada a seguir
head.addInlineScript(code, options)Corre JavaScript na página, a única forma de chegar a globais do window como dataLayer e gtag
head.setMeta(name, content)Define uma meta tag name, como description ou robots
head.setMetaProperty(property, content)Define uma meta tag property, que é o que o Open Graph usa
head.setLink(rel, href, options)Define uma tag link, como canonical ou um alternate por idioma
head.setJsonLd(data, options)Escreve um bloco JSON-LD
head.setTitle(title)Define o título da página. Por omissão é usado o nome da história

Todas as chamadas são idempotentes. Um bloco que corre outra vez atualiza as suas tags em vez de adicionar uma segunda cópia, por isso uma tag nunca é carregada duas vezes nem uma visita é contada duas vezes.

Uma ação Custom Code não tem head. Para enviar um evento a partir de uma ação, use o snippet do Measurement Protocol do Google Analytics, que é apenas um fetch e funciona em qualquer bloco.

O objeto cyango

Existem cinco namespaces:

NamespacePara que serve
cyango.utilsAuxiliares: encontrar entidades, guardar variáveis, ler inputs GUI, detetar o dispositivo
cyango.storyStateLer e controlar a história: cenas, idioma, ativos, XR
cyango.uiStateEstado da app e da interface: carregamento, controlos de câmara, modais
cyango.timelineStateTimeline da cena e reprodução de media
cyango.typesEnums usados como argumentos e para comparações

Os valores que lê estão em direto, como cyango.storyState.activeSceneId. As funções que chama executam uma ação, como cyango.storyState.setActiveScene(id).

Variáveis

As variáveis globais duram toda a sessão e sobrevivem às mudanças de cena. Use-as para passar dados de uma ação para outra.

MétodoDescrição
cyango.utils.setGlobalVar(key, value)Guardar qualquer valor sob uma chave
cyango.utils.getGlobalVar(key)Ler um valor guardado
cyango.utils.deleteGlobalVar(key)Remover uma chave (devolve boolean)
cyango.utils.clearGlobalVars()Remover todas as variáveis
cyango.utils.globalVarsO registo completo, como snapshot
// Ao clicar num botão: contar os cliques e agir no terceiro
const clicks = (cyango.utils.getGlobalVar('clicks') ?? 0) + 1;
cyango.utils.setGlobalVar('clicks', clicks);

if (clicks < 3) return;

const scene = cyango.storyState.activeStoryJson.scenes.find((s) => s.name === 'Reward');
if (scene) cyango.storyState.setActiveScene(scene.id);

Encontrar entidades e cenas

Método ou valorDevolve
cyango.utils.getActiveScene()A cena atual (IScene), ou null
cyango.utils.getEntityByName(entities, name)A primeira entidade com esse nome, ou null
cyango.utils.getEntityById(entities, id)A entidade pelo seu id, ou null
cyango.utils.thisEntityA entidade a que esta ação está associada
cyango.storyState.activeSceneIdId da cena atual
cyango.storyState.activeStoryJsonO documento completo da história, incluindo .scenes
const scene = cyango.utils.getActiveScene();
const logo = cyango.utils.getEntityByName(scene.entities, 'Logo');

Ler campos de input GUI

As entidades de campo de input capturam o que o visitante escreve. Leia ou defina esse valor pelo id da entidade do input. O valor é mantido mesmo que o campo seja escondido e mostrado de novo.

MétodoDescrição
cyango.utils.getGuiInputValue(entityId)O texto atual (string), ou null se nunca foi definido
cyango.utils.setGuiInputValue(entityId, value)Definir o texto do campo
cyango.utils.clearGuiInputValue(entityId)Esvaziar o campo
// Num botão Submit: ler um campo de email e guardá-lo
const scene = cyango.utils.getActiveScene();
const emailField = cyango.utils.getEntityByName(scene.entities, 'EmailInput');

const email = cyango.utils.getGuiInputValue(emailField.id);
cyango.utils.setGlobalVar('email', email);

cyango.utils.setGuiInputValue(emailField.id, ''); // limpar após submeter

Fazer scroll em contentores GUI

Para contentores GUI cujo conteúdo faz scroll, como listas e painéis:

MétodoDescrição
cyango.utils.getGuiScrollPosition(entityId)Deslocamento { x, y } atual (chame trackGuiScroll primeiro)
cyango.utils.getGuiMaxScrollPosition(entityId)Deslocamento de scroll máximo
cyango.utils.setGuiScrollPosition(entityId, x, y)Saltar para um deslocamento
cyango.utils.scrollGuiBy(entityId, dx, dy)Deslocamento a partir da posição atual
cyango.utils.trackGuiScroll(entityId) e untrackGuiScroll(entityId)Iniciar e parar o registo do scroll do utilizador
cyango.utils.lockGuiScroll(entityId) e unlockGuiScroll(entityId)Bloquear e permitir o scroll do utilizador
Método ou valorDescrição
cyango.storyState.setActiveScene(sceneId)Ir para uma cena, opcionalmente com uma transição
cyango.storyState.setActiveLanguage(lang)Mudar de idioma (dispara On Language Changed)
cyango.storyState.triggerAction(action, entityId?)Correr um objeto de ação diretamente
cyango.uiState.openUrl(url)Abrir um URL externo
cyango.storyState.activeLanguage e availableLanguagesIdioma atual e idiomas disponíveis
// Enviar visitantes portugueses para uma cena localizada
if (cyango.storyState.activeLanguage === cyango.types.LanguageTypes.pt_PT) {
  const scene = cyango.storyState.activeStoryJson.scenes.find((s) => s.name === 'Intro PT');
  if (scene) cyango.storyState.setActiveScene(scene.id);
}

AR e VR

Método ou valorDescrição
cyango.storyState.enterAR(), enterVR(), exitXR()Entrar ou sair dos modos imersivos
cyango.storyState.isAR, isVR, isMobileARSe um modo está atualmente ativo

Timeline e media

Método ou valorDescrição
cyango.timelineState.setPlayingMode(mode)Reproduzir ou pausar a timeline da cena. Veja cyango.types.PlayingModes
cyango.timelineState.controlMedia(mode)Controlar a media da cena: 'play', 'pause', 'stop', 'mute', 'unmute', 'seek'
cyango.timelineState.setElapsedTime(ms)Avançar na timeline
cyango.timelineState.elapsedTimeTempo atual, em milissegundos
cyango.timelineState.setPlayingMode(cyango.types.PlayingModes.PLAY);

Dispositivo e ambiente

Método ou valorDevolve
cyango.utils.detectDeviceType()"iPad", "iPhone", "Android", "Windows", "Mac", ou "Unknown"
cyango.utils.detectBrowser()Nome do browser, como "Apple Safari" ou "Google Chrome"
cyango.uiState.selectedBreakpointBreakpoint atual. Veja cyango.types.BreakpointStateTypes
cyango.utils.getWindowLocation()O objeto Location, incluindo o URL e a query string
cyango.utils.getNavigator()O objeto Navigator
if (cyango.utils.detectDeviceType() === 'iPhone') {
  // mostrar uma dica específica para telemóvel
}

Tipos

cyango.types fornece os enums usados em toda a API. Use-os para argumentos e comparações:

ActionType, EventType, PlayingModes, TransitionType, EntityTypes, MaterialTypes, BreakpointStateTypes, SceneTypes, AssetCategories, AssetFileTypes, AssetMimeTypes, LanguageTypes.

Exemplo: um formulário de inscrição

// No On Click de um botão Continue
const scene = cyango.utils.getActiveScene();
const nameField = cyango.utils.getEntityByName(scene.entities, 'NameInput');
const name = (cyango.utils.getGuiInputValue(nameField.id) ?? '').trim();

// Nada escrito, por isso limpar o campo e ficar nesta cena
if (!name) {
  cyango.utils.clearGuiInputValue(nameField.id);
  return;
}

// Guardar o nome, enviá-lo para o seu backend, depois continuar
cyango.utils.setGlobalVar('visitorName', name);

await fetch('https://example.com/signups', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ name }),
});

const next = cyango.storyState.activeStoryJson.scenes.find((s) => s.name === 'Welcome');
if (next) cyango.storyState.setActiveScene(next.id);