From 98a7ff6886bbeaba6c11fe4492294ee0834c5a41 Mon Sep 17 00:00:00 2001 From: Pravus Date: Thu, 27 Aug 2026 02:59:43 +0200 Subject: [PATCH] feat: engine-info loading-screen visible --- .../sdk7-updates-since-2026-01-21.mdc | 22 ++++++++++++ ai-sdk-context/sdk7-examples.mdc | 22 ++++++++++++ .../sdk7/interactivity/runtime-data.md | 36 ++++++++++++++++++- creator/sdk7/interactivity/runtime-data.md | 34 ++++++++++++++++++ 4 files changed, 113 insertions(+), 1 deletion(-) diff --git a/ai-sdk-context/overview/sdk7-updates-since-2026-01-21.mdc b/ai-sdk-context/overview/sdk7-updates-since-2026-01-21.mdc index 37846fc1..d06626a7 100644 --- a/ai-sdk-context/overview/sdk7-updates-since-2026-01-21.mdc +++ b/ai-sdk-context/overview/sdk7-updates-since-2026-01-21.mdc @@ -178,3 +178,25 @@ Many SDK APIs that previously required `{ $case: '...', ... }` objects now provi - `LightSource.Type.Point({ ... })` - `Tween.Mode.Move({ ... })` + +## `EngineInfo.sceneHidden` (detect when the loading screen fades out) + +The `EngineInfo` component (on `engine.RootEntity`) gained a `sceneHidden: boolean` field: it reports whether the scene is currently covered by the Explorer's fullscreen UI. + +Today it is driven by the **loading screen**: `sceneHidden` is `true` while the loading screen is up, and flips to `false` the moment it fades out. This is the only way for a scene to know when the player first actually sees it — use it to time intro cinematics, welcome sounds, opening UI, or analytics events that shouldn't fire behind the loading screen. + +```typescript +import { EngineInfo, engine } from '@dcl/sdk/ecs' + +engine.addSystem(function waitForSceneRevealed() { + const engineInfo = EngineInfo.getOrNull(engine.RootEntity) + if (!engineInfo || engineInfo.sceneHidden) return + + // Only run once + engine.removeSystem(waitForSceneRevealed) + + console.log('The loading screen just faded out') +}) +``` + +The scene keeps ticking normally while `sceneHidden` is `true` — it just isn't displayed. Don't use it to pause scene logic. On Explorer versions that predate the field it stays at its default `false`, so a scene that only waits for `sceneHidden === false` still runs (it just won't be synced to the fade-out). diff --git a/ai-sdk-context/sdk7-examples.mdc b/ai-sdk-context/sdk7-examples.mdc index 1ac823e2..1feac9c1 100644 --- a/ai-sdk-context/sdk7-examples.mdc +++ b/ai-sdk-context/sdk7-examples.mdc @@ -431,6 +431,9 @@ engine.addSystem((deltaTime) => { // Get current tick number const currentTick = engineInfo.tickNumber + // Is the scene covered by the Explorer's fullscreen UI (e.g. the loading screen)? + const isHidden = engineInfo.sceneHidden + // Example: Log every 100 frames if (currentFrame % 100 === 0) { console.log(`Runtime: ${runtime.toFixed(2)}s, Frame: ${currentFrame}, Tick: ${currentTick}`) @@ -438,6 +441,25 @@ engine.addSystem((deltaTime) => { }) ``` +### React to the Loading Screen Fading Out +`EngineInfo.sceneHidden` is `true` while the Explorer's loading screen covers the scene, and flips to `false` the moment it fades out. This is the only way to know when the player first sees the scene, so use it to time intro cinematics, welcome sounds, opening UI, or analytics events. + +```typescript +import { EngineInfo, engine } from '@dcl/sdk/ecs' + +engine.addSystem(function waitForSceneRevealed() { + const engineInfo = EngineInfo.getOrNull(engine.RootEntity) + if (!engineInfo || engineInfo.sceneHidden) return + + // Only run once + engine.removeSystem(waitForSceneRevealed) + + console.log('The loading screen just faded out, start the intro here') +}) +``` + +The scene keeps running normally while `sceneHidden` is `true` — it just isn't being displayed. Don't use this flag to pause scene logic, use it to time what the player is meant to witness. + ## Player Data & Camera Controls ### Player Position and Rotation diff --git a/creator-esp/sdk7/interactivity/runtime-data.md b/creator-esp/sdk7/interactivity/runtime-data.md index a7f1b0ae..0049ba03 100644 --- a/creator-esp/sdk7/interactivity/runtime-data.md +++ b/creator-esp/sdk7/interactivity/runtime-data.md @@ -138,6 +138,8 @@ engine.addSystem((deltaTime) => { engineInfo.tickNumber + '\ntotalRuntime: ' + engineInfo.totalRuntime + + '\nsceneHidden: ' + + engineInfo.sceneHidden + '\n--------------' ) }) @@ -148,11 +150,43 @@ El componente `EngineInfo` contiene los siguientes datos: * `frame_number`: Contador de frames del motor * `total_runtime`: Runtime total de esta escena en segundos * `tick_number`: Contador de ticks de la escena según [ADR-148](https://adr.decentraland.org/adr/ADR-148) +* `scene_hidden`: Si la escena está actualmente oculta detrás de la UI de pantalla completa del Explorer {% hint style="warning" %} **📔 Nota**: El componente `EngineInfo` debe importarse mediante -> `import { Vector3, Quaternion } from "@dcl/sdk/ecs"` +> `import { EngineInfo } from "@dcl/sdk/ecs"` Consulta [Importaciones](../getting-started/coding-scenes.md#imports) para saber cómo manejarlas fácilmente. {% endhint %} + +### Reaccionar a la desaparición de la pantalla de carga + +El campo `scene_hidden` indica si el jugador realmente puede ver tu escena, o si está cubierta por la UI de pantalla completa del Explorer. Mientras la pantalla de carga está visible, `sceneHidden` vale `true`. En el momento en que la pantalla de carga se desvanece y el jugador ve el mundo por primera vez, pasa a `false`. + +Esta es la única forma que tiene una escena de saber cuándo ocurre esa primera revelación. Úsala para retener todo aquello que, de otro modo, sucedería detrás de la pantalla de carga y el jugador se perdería: cinemáticas de introducción, sonidos de bienvenida, un tween que solo se entiende si se mira, una UI de apertura, o un evento de analítica que solo debería contar cuando el jugador realmente está ahí. + +```ts +import { engine, EngineInfo } from '@dcl/sdk/ecs' + +function onSceneRevealed() { + // El jugador ya está viendo la escena, arranca la introducción acá + console.log('La pantalla de carga acaba de desaparecer') +} + +engine.addSystem(function waitForSceneRevealed() { + const engineInfo = EngineInfo.getOrNull(engine.RootEntity) + if (!engineInfo || engineInfo.sceneHidden) return + + // Ejecutar una sola vez + engine.removeSystem(waitForSceneRevealed) + onSceneRevealed() +}) +``` + +{% hint style="warning" %} +**📔 Nota**: Tu escena sigue ejecutándose normalmente mientras `sceneHidden` vale `true`, simplemente no se está mostrando. No uses este campo para pausar la lógica de tu escena, úsalo para temporizar aquello que el jugador debe presenciar. + +`scene_hidden` requiere un `@dcl/sdk` actualizado y una versión reciente del Decentraland Explorer. En clientes más antiguos el campo mantiene su valor por defecto `false`, así que una escena que lo espera igual se ejecuta — simplemente no queda sincronizada con la desaparición de la pantalla de carga. +{% endhint %} + diff --git a/creator/sdk7/interactivity/runtime-data.md b/creator/sdk7/interactivity/runtime-data.md index 74875a8b..174a5c85 100644 --- a/creator/sdk7/interactivity/runtime-data.md +++ b/creator/sdk7/interactivity/runtime-data.md @@ -144,6 +144,8 @@ engine.addSystem((deltaTime) => { engineInfo.tickNumber + '\ntotalRuntime: ' + engineInfo.totalRuntime + + '\nsceneHidden: ' + + engineInfo.sceneHidden + '\n--------------' ) }) @@ -154,6 +156,7 @@ The `EngineInfo`component holds the following data: * `frame_number`: Frame counter of the engine * `total_runtime`: Total runtime of this scene in seconds * `tick_number`: Tick counter of the scene as per [ADR-148](https://adr.decentraland.org/adr/ADR-148) +* `scene_hidden`: Whether the scene is currently hidden behind the Explorer's fullscreen UI {% hint style="warning" %} **📔 Note**: The `EngineInfo` component must be imported via @@ -162,3 +165,34 @@ The `EngineInfo`component holds the following data: See [Imports](../getting-started/coding-scenes.md#imports) for how to handle these easily. {% endhint %} + +### React to the loading screen fading out + +The `scene_hidden` field tells you if the player can actually see your scene, or if it's covered by the Explorer's fullscreen UI. While the loading screen is up, `sceneHidden` is `true`. The moment the loading screen fades out and the player gets their first look at the world, it turns `false`. + +This is the only way for a scene to know when that first reveal happens. Use it to hold back anything that would otherwise play out behind the loading screen, and be missed by the player: intro cinematics, welcome sounds, a tween that only reads well if it's watched, an opening UI, or an analytics event that should only count once the player is really there. + +```ts +import { engine, EngineInfo } from '@dcl/sdk/ecs' + +function onSceneRevealed() { + // The player is now looking at the scene, start the intro here + console.log('The loading screen just faded out') +} + +engine.addSystem(function waitForSceneRevealed() { + const engineInfo = EngineInfo.getOrNull(engine.RootEntity) + if (!engineInfo || engineInfo.sceneHidden) return + + // Only run once + engine.removeSystem(waitForSceneRevealed) + onSceneRevealed() +}) +``` + +{% hint style="warning" %} +**📔 Note**: Your scene keeps running normally while `sceneHidden` is `true`, it's only not being displayed. Don't use this field to pause your scene's logic, use it to time what the player is meant to witness. + +`scene_hidden` requires an up-to-date `@dcl/sdk` and a recent version of the Decentraland Explorer. On older clients the field stays at its default value of `false`, so a scene that waits on it still runs — it just won't be in sync with the loading screen fade-out. +{% endhint %} +