@3dsource/angular-unreal-module 0.0.139 → 0.0.142

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,370 +1,370 @@
1
- # @3dsource/angular-unreal-module
2
-
3
- A set of standalone Angular components, services, and providers for integrating Unreal Engine (WebRTC) scenes into Angular applications. It facilitates communication between Angular and Unreal Engine and enables interactive 3D experiences.
4
-
5
- ## Overview
6
-
7
- This package provides:
8
-
9
- - Standalone Unreal scene component to embed UE stream
10
- - Communication bridge (commands, UI interactions, input data)
11
- - Callback listener for Unreal events and command responses
12
- - NgRx state and effects for 3D stream lifecycle
13
- - Config and utilities for telemetry, errors, and regions ping
14
- - Auto-reconnection support for WebRTC/DataChannel failures
15
- - File receiving from Unreal Engine
16
- - Analytics, FPS monitoring, and stream status telemetry
17
- - Playwright testing mode with mock services
18
-
19
- ## Installation
20
-
21
- ### Prerequisites
22
-
23
- - Angular 18+
24
- - NgRx store and effects (v18+)
25
- - Angular CDK (v18+) — used for dialog overlays
26
- - `provideHttpClient()` — required by internal services (telemetry, signalling, regions ping, error reporting)
27
-
28
- ### Peer Dependencies
29
-
30
- This library requires the following peer dependencies (match or exceed versions):
31
-
32
- ```json
33
- {
34
- "@3dsource/source-ui-native": ">=1.0.9",
35
- "@3dsource/types-unreal": ">=0.0.7",
36
- "@3dsource/utils": ">=1.0.21",
37
- "@angular/cdk": ">=18.0.0",
38
- "@angular/common": ">=18.0.0",
39
- "@angular/core": ">=18.0.0",
40
- "@angular/forms": ">=18.0.0",
41
- "@ngrx/effects": ">=18.0.0",
42
- "@ngrx/store": ">=18.0.0"
43
- }
44
- ```
45
-
46
- ### Library Installation
47
-
48
- ```shell
49
- npm i @3dsource/angular-unreal-module
50
- ```
51
-
52
- ## Usage
53
-
54
- The API is fully standalone (no NgModule). Use providers and components as shown below.
55
-
56
- ### 1) Provide the module services and store slice
57
-
58
- Add providers in your application bootstrap (e.g., `app.config.ts`):
59
-
60
- > **⚠️ Important:** `UNREAL_CONFIG` is **required** — multiple internal services inject it without `{ optional: true }`. Omitting it will cause a `NullInjectorError` at runtime. You can provide it with an empty object `{}` as a minimum.
61
-
62
- ```ts
63
- import { ApplicationConfig } from '@angular/core';
64
- import { provideRouter } from '@angular/router';
65
- import { provideHttpClient } from '@angular/common/http';
66
- import { provideStore } from '@ngrx/store';
67
- import { provideEffects } from '@ngrx/effects';
68
- import { provideUnrealModule, UNREAL_CONFIG } from '@3dsource/angular-unreal-module';
69
-
70
- export const appConfig: ApplicationConfig = {
71
- providers: [
72
- provideRouter([]),
73
- provideHttpClient(),
74
-
75
- // Root NgRx (if not already added in your app)
76
- provideStore(),
77
- provideEffects(),
78
-
79
- // Required: Unreal initial configuration
80
- {
81
- provide: UNREAL_CONFIG,
82
- useValue: {
83
- customErrorsEndpoint: '', // Endpoint for custom error reporting
84
- commandTelemetryReceiver: '', // Endpoint for command telemetry
85
- regionsPingUrl: '', // URL prefix for regions latency ping
86
- screenLockerContainerId: '', // DOM container id for screen locker overlay
87
- dataChannelConnectionTimeout: 8000, // Timeout in ms for data channel connection (default: 8000)
88
- playwright: false, // Mirrors the provider flag for services/effects
89
- reconnect: {
90
- // Auto-reconnection configuration
91
- enabled: true, // Enable auto-reconnection (default: true)
92
- maxAttempts: 3, // Max reconnection attempts (default: 3)
93
- delayMs: 1000, // Delay between attempts in ms (default: 1000)
94
- onIceFailure: true, // Reconnect on ICE connection failure (default: true)
95
- onDataChannelClose: true, // Reconnect on DataChannel close (default: true)
96
- },
97
- },
98
- },
99
-
100
- // Core Unreal providers (adds feature state + effects internally).
101
- // playwright/testing mode is set via UNREAL_CONFIG above.
102
- // Opt into extra features as needed — see "Bundle size & features" below.
103
- provideUnrealModule(),
104
- ],
105
- };
106
- ```
107
-
108
- #### Minimal configuration
109
-
110
- If you don't need custom endpoints, provide `UNREAL_CONFIG` with an empty object:
111
-
112
- ```ts
113
- { provide: UNREAL_CONFIG, useValue: {} },
114
- provideUnrealModule(),
115
- ```
116
-
117
- ### 2) Use the Unreal scene component
118
-
119
- Import the component into a standalone component and use it in the template.
120
-
121
- ```ts
122
- import { Component } from '@angular/core';
123
- import { UnrealSceneComponent } from '@3dsource/angular-unreal-module';
124
-
125
- @Component({
126
- selector: 'app-root',
127
- standalone: true,
128
- imports: [UnrealSceneComponent],
129
- template: ` <app-unreal-scene [isStudio]="false" [useContainerAsSizeProvider]="true" [studioResolutionSize]="{ width: 1920, height: 1080 }" (changeMouseOverScene)="onHover($event)"> </app-unreal-scene> `,
130
- })
131
- export class AppComponent {
132
- onHover(isOver: boolean) {
133
- // handle mouse over scene
134
- }
135
- }
136
- ```
137
-
138
- Component selector: `<app-unreal-scene>`
139
-
140
- Inputs:
141
-
142
- | Input | Type | Default |
143
- | ---------------------------- | ----------------------------------- | ------------------------------- |
144
- | `isStudio` | `boolean` | `false` |
145
- | `useContainerAsSizeProvider` | `boolean` | `true` |
146
- | `studioResolutionSize` | `{ width: number; height: number }` | `{ width: 1920, height: 1080 }` |
147
-
148
- Outputs:
149
-
150
- | Output | Type |
151
- | ---------------------- | --------------------------- |
152
- | `changeMouseOverScene` | `OutputEmitterRef<boolean>` |
153
-
154
- ### 3) Send commands / interactions to Unreal
155
-
156
- Inject `UnrealCommunicatorService` to send commands or UI interactions. Types for command packets are provided by `@3dsource/types-unreal`.
157
-
158
- There are three sending methods — choose based on your needs:
159
-
160
- | Method | Description |
161
- | --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
162
- | `sendCommandToUnreal` | Full pipeline: adds `correlationId`, records telemetry, dispatches NgRx `commandStarted` action. **Recommended for application commands.** |
163
- | `emitUIInteraction` | Sends the packet as a raw `UIInteraction` message. No telemetry or store dispatch. |
164
- | `emitCommand` | Sends the packet as a raw `Command` message (for console commands, resolution changes, etc.). |
165
-
166
- ```ts
167
- import { Component, inject } from '@angular/core';
168
- import { UnrealCommunicatorService } from '@3dsource/angular-unreal-module';
169
- import { MetaBoxCommand } from '@3dsource/types-unreal';
170
- import type { MetaBoxCommandPacket } from '@3dsource/types-unreal';
171
-
172
- @Component({ standalone: true, template: '' })
173
- export class MyComponent {
174
- private unreal = inject(UnrealCommunicatorService);
175
-
176
- sendSomeCommand() {
177
- // Recommended: use sendCommandToUnreal for full telemetry + store tracking
178
- this.unreal.sendCommandToUnreal({
179
- command: MetaBoxCommand.FChangeResolutionCommand,
180
- payload: { resolution: { x: 1920, y: 1080 } },
181
- });
182
- }
183
-
184
- sendRawUIInteraction() {
185
- // Low-level: sends UIInteraction message without telemetry tracking
186
- const packet = {
187
- command: 'CustomCommand',
188
- payload: { key: 'value' },
189
- } as MetaBoxCommandPacket;
190
- this.unreal.emitUIInteraction(packet);
191
- }
192
- }
193
- ```
194
-
195
- ### 4) Store integration (actions & selectors)
196
-
197
- The module registers an NgRx feature state `commandsFeature`. You can dispatch actions and select state in your components:
198
-
199
- ```ts
200
- import { inject } from '@angular/core';
201
- import { Store } from '@ngrx/store';
202
- import { startStream, setConfig, setOrchestrationContext, disconnectStream, selectTotalProgress, selectShowLoader, commandsFeature } from '@3dsource/angular-unreal-module';
203
-
204
- // Dispatch actions
205
- const store = inject(Store);
206
- store.dispatch(startStream({ config: { autoStart: true, warnTimeout: 120 } }));
207
-
208
- // Select state
209
- const progress = store.selectSignal(selectTotalProgress);
210
- const isVideoPlaying = store.selectSignal(commandsFeature.selectIsVideoPlaying);
211
- const dataChannelConnected = store.selectSignal(commandsFeature.selectDataChannelConnected);
212
- ```
213
-
214
- **Key selectors:**
215
-
216
- - `selectTotalProgress` — Scene load progress (0–1 float)
217
- - `selectShowLoader` — Whether loader screen should be visible
218
- - `selectShowReconnectPopup` — Whether reconnect popup should be shown
219
- - `selectIsVideoPlayingAndDataChannelConnected` — Combined readiness check
220
- - `selectStreamConfig` — Current stream configuration
221
- - `commandsFeature.selectCirrusConnected` — Signalling server connection status
222
- - `commandsFeature.selectDataChannelConnected` — Data channel status
223
- - `commandsFeature.selectViewportReady` — Viewport readiness
224
-
225
- **Key actions:**
226
-
227
- - `startStream` — Start streaming with config
228
- - `setConfig` — Update stream configuration
229
- - `setOrchestrationContext` — Set orchestration URLs and environment
230
- - `disconnectStream` — Disconnect with reason
231
- - `destroyUnrealScene` — Full teardown
232
- - `reconnectPeer` — Trigger peer reconnection
233
-
234
- ### 5) Listen for Unreal callbacks
235
-
236
- Inject `UnrealCallbackService` to listen for callback events from Unreal Engine and to observe command responses.
237
-
238
- There are two methods:
239
-
240
- | Method | Description |
241
- | ------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
242
- | `fromUnrealCallback` | Listens for callbacks matching a command or event key. Supports MetaBox commands and custom Unreal callback events. Returns `Observable<UnrealCallbackDescriptor[K]>`. |
243
- | `observeCommandResponse` | Sends a command and waits for its matching response by `correlationId`. Returns `Observable<MetaBoxCommandList[K]>`. Includes timeout and error handling. |
244
-
245
- **Custom Unreal callback events** (defined in `UnrealCallbackEventMap`):
246
-
247
- | Event | Payload Type |
248
- | -------------------------- | --------------------------------------------------- |
249
- | `onSceneState` | `FSceneState` |
250
- | `onFocusObject` | `FProductPayload` |
251
- | `cameraChanged` | `FCameraChangedPayload` |
252
- | `onObjectTransformChanged` | `{ objectName: string; transform: FTransformJson }` |
253
- | `onChangeSequence` | `unknown` |
254
- | `onFinishedSequence` | `unknown` |
255
-
256
- ```ts
257
- import { Component, inject } from '@angular/core';
258
- import { UnrealCallbackService } from '@3dsource/angular-unreal-module';
259
- import { UnrealCommunicatorService } from '@3dsource/angular-unreal-module';
260
- import { MetaBoxCommand } from '@3dsource/types-unreal';
261
-
262
- @Component({ standalone: true, template: '' })
263
- export class MyComponent {
264
- private callbackService = inject(UnrealCallbackService);
265
- private communicator = inject(UnrealCommunicatorService);
266
-
267
- listenForCallbacks() {
268
- // Listen for a MetaBox command callback
269
- this.callbackService.fromUnrealCallback(MetaBoxCommand.FLoadProductCommand).subscribe((data) => console.log('Product loaded:', data));
270
-
271
- // Listen for a custom Unreal event
272
- this.callbackService.fromUnrealCallback('cameraChanged').subscribe((data) => console.log('Camera changed:', data));
273
- }
274
-
275
- sendAndObserve() {
276
- // Send a command and observe its response (with correlationId matching)
277
- this.callbackService
278
- .observeCommandResponse(
279
- { command: MetaBoxCommand.FLoopBackCommand },
280
- (data) => this.communicator.sendCommandToUnreal(data),
281
- 60000, // timeout in ms (default: 60000)
282
- true, // emit on timeout (default: true)
283
- )
284
- .subscribe((response) => console.log('Response:', response));
285
- }
286
- }
287
- ```
288
-
289
- ## Exported API
290
-
291
- ### Components
292
-
293
- | Component | Selector | Description |
294
- | -------------------------------- | ------------------ | -------------------------------------- |
295
- | `UnrealSceneComponent` | `app-unreal-scene` | Main scene container with video stream |
296
- | `AfkTimeoutModalComponent` | — | AFK timeout warning modal |
297
- | `FreezeFrameComponent` | — | Freeze frame overlay |
298
- | `LowBandwidthModalComponent` | — | Low bandwidth warning modal |
299
- | `LowBandwidthIndicatorComponent` | — | Low bandwidth indicator |
300
- | `ImageLoadingSrcComponent` | — | Loading image overlay |
301
- | `IntroSrcComponent` | — | Intro image/video overlay |
302
- | `VideoStatsComponent` | — | Video statistics display |
303
- | `StatGraphComponent` | — | Statistics graph |
304
- | `WebrtcErrorModalComponent` | — | WebRTC error modal |
305
-
306
- ### Services
307
-
308
- | Service | Description |
309
- | ------------------------------ | --------------------------------------------------------------- |
310
- | `UnrealCommunicatorService` | Send commands and UI interactions to Unreal |
311
- | `UnrealCallbackService` | Listen for Unreal callback events and observe command responses |
312
- | `AggregatorService` | Aggregates data channel messages from Unreal |
313
- | `SignallingService` | Manages WebSocket signalling connection |
314
- | `VideoService` | Manages video element and stats |
315
- | `WebRtcPlayerService` | Manages WebRTC peer connection |
316
- | `FreezeFrameService` | Handles freeze frame images |
317
- | `AFKService` | AFK (away from keyboard) detection and timeout |
318
- | `DevModeService` | Toggle dev mode for debugging |
319
- | `FileReceiverService` | Receives files from Unreal via data channel |
320
- | `FileHandlerService` | Processes received files |
321
- | `RegionsPingService` | Pings regions to determine latency |
322
- | `CommandTelemetryService` | Records command telemetry |
323
- | `StreamStatusTelemetryService` | Reports stream status telemetry |
324
- | `AnalyticsService` | Analytics event tracking |
325
- | `FpsMonitorService` | FPS monitoring |
326
-
327
- ### Pipes
328
-
329
- | Pipe | Description |
330
- | -------------- | ------------------------------- |
331
- | `SafeHtmlPipe` | Bypasses Angular HTML sanitizer |
332
-
333
- ### Interfaces
334
-
335
- | Interface | Description |
336
- | -------------------------- | ---------------------------------------------------------------------------- |
337
- | `UnrealInitialConfig` | Shape for `UNREAL_CONFIG` injection token |
338
- | `ReconnectConfig` | Auto-reconnection behavior configuration |
339
- | `StreamConfig` | Stream configuration (autoStart, warnTimeout) |
340
- | `StreamResolutionProps` | Stream resolution width/height |
341
- | `UnrealCallbackEventMap` | Custom Unreal callback events pushed from Unreal via data channel |
342
- | `UnrealCallbackDescriptor` | Combined map of MetaBoxCommandList and UnrealCallbackEventMap callback types |
343
-
344
- ## Features
345
-
346
- - Standalone Unreal Scene Component
347
- - Command and UI Interaction API via `UnrealCommunicatorService`
348
- - Callback listener and command response observer via `UnrealCallbackService`
349
- - Event-driven status UI (freeze frame, video stats, play overlay, AFK, low bandwidth)
350
- - NgRx-powered state management and effects
351
- - **Required** initial configuration via `UNREAL_CONFIG` injection token
352
- - Auto-reconnection on WebRTC/DataChannel failures (configurable)
353
- - File receiving from Unreal Engine via data channel
354
- - Analytics and FPS monitoring
355
- - Playwright testing mode with mock service substitution
356
-
357
- ## Examples
358
-
359
- Check the demo application for complete usage examples:
360
-
361
- ```shell
362
- npm run demo:start
363
- ```
364
-
365
- See also: `projects/demo/src/app/demo-layout/info-pages/unreal-scene-demo/constants/unreal.routes.ts` for a real-world provider configuration example.
366
-
367
- ## Engine requirements
368
-
369
- - Node.js: >=20
370
- - npm: >9
1
+ # @3dsource/angular-unreal-module
2
+
3
+ A set of standalone Angular components, services, and providers for integrating Unreal Engine (WebRTC) scenes into Angular applications. It facilitates communication between Angular and Unreal Engine and enables interactive 3D experiences.
4
+
5
+ ## Overview
6
+
7
+ This package provides:
8
+
9
+ - Standalone Unreal scene component to embed UE stream
10
+ - Communication bridge (commands, UI interactions, input data)
11
+ - Callback listener for Unreal events and command responses
12
+ - NgRx state and effects for 3D stream lifecycle
13
+ - Config and utilities for telemetry, errors, and regions ping
14
+ - Auto-reconnection support for WebRTC/DataChannel failures
15
+ - File receiving from Unreal Engine
16
+ - Analytics, FPS monitoring, and stream status telemetry
17
+ - Playwright testing mode with mock services
18
+
19
+ ## Installation
20
+
21
+ ### Prerequisites
22
+
23
+ - Angular 18+
24
+ - NgRx store and effects (v18+)
25
+ - Angular CDK (v18+) — used for dialog overlays
26
+ - `provideHttpClient()` — required by internal services (telemetry, signalling, regions ping, error reporting)
27
+
28
+ ### Peer Dependencies
29
+
30
+ This library requires the following peer dependencies (match or exceed versions):
31
+
32
+ ```json
33
+ {
34
+ "@3dsource/source-ui-native": ">=1.0.9",
35
+ "@3dsource/types-unreal": ">=0.0.7",
36
+ "@3dsource/utils": ">=1.0.21",
37
+ "@angular/cdk": ">=18.0.0",
38
+ "@angular/common": ">=18.0.0",
39
+ "@angular/core": ">=18.0.0",
40
+ "@angular/forms": ">=18.0.0",
41
+ "@ngrx/effects": ">=18.0.0",
42
+ "@ngrx/store": ">=18.0.0"
43
+ }
44
+ ```
45
+
46
+ ### Library Installation
47
+
48
+ ```shell
49
+ npm i @3dsource/angular-unreal-module
50
+ ```
51
+
52
+ ## Usage
53
+
54
+ The API is fully standalone (no NgModule). Use providers and components as shown below.
55
+
56
+ ### 1) Provide the module services and store slice
57
+
58
+ Add providers in your application bootstrap (e.g., `app.config.ts`):
59
+
60
+ > **⚠️ Important:** `UNREAL_CONFIG` is **required** — multiple internal services inject it without `{ optional: true }`. Omitting it will cause a `NullInjectorError` at runtime. You can provide it with an empty object `{}` as a minimum.
61
+
62
+ ```ts
63
+ import { ApplicationConfig } from '@angular/core';
64
+ import { provideRouter } from '@angular/router';
65
+ import { provideHttpClient } from '@angular/common/http';
66
+ import { provideStore } from '@ngrx/store';
67
+ import { provideEffects } from '@ngrx/effects';
68
+ import { provideUnrealModule, UNREAL_CONFIG } from '@3dsource/angular-unreal-module';
69
+
70
+ export const appConfig: ApplicationConfig = {
71
+ providers: [
72
+ provideRouter([]),
73
+ provideHttpClient(),
74
+
75
+ // Root NgRx (if not already added in your app)
76
+ provideStore(),
77
+ provideEffects(),
78
+
79
+ // Required: Unreal initial configuration
80
+ {
81
+ provide: UNREAL_CONFIG,
82
+ useValue: {
83
+ customErrorsEndpoint: '', // Endpoint for custom error reporting
84
+ commandTelemetryReceiver: '', // Endpoint for command telemetry
85
+ regionsPingUrl: '', // URL prefix for regions latency ping
86
+ screenLockerContainerId: '', // DOM container id for screen locker overlay
87
+ dataChannelConnectionTimeout: 8000, // Timeout in ms for data channel connection (default: 8000)
88
+ playwright: false, // Mirrors the provider flag for services/effects
89
+ reconnect: {
90
+ // Auto-reconnection configuration
91
+ enabled: true, // Enable auto-reconnection (default: true)
92
+ maxAttempts: 3, // Max reconnection attempts (default: 3)
93
+ delayMs: 1000, // Delay between attempts in ms (default: 1000)
94
+ onIceFailure: true, // Reconnect on ICE connection failure (default: true)
95
+ onDataChannelClose: true, // Reconnect on DataChannel close (default: true)
96
+ },
97
+ },
98
+ },
99
+
100
+ // Core Unreal providers (adds feature state + effects internally).
101
+ // playwright/testing mode is set via UNREAL_CONFIG above.
102
+ // Opt into extra features as needed — see "Bundle size & features" below.
103
+ provideUnrealModule(),
104
+ ],
105
+ };
106
+ ```
107
+
108
+ #### Minimal configuration
109
+
110
+ If you don't need custom endpoints, provide `UNREAL_CONFIG` with an empty object:
111
+
112
+ ```ts
113
+ { provide: UNREAL_CONFIG, useValue: {} },
114
+ provideUnrealModule(),
115
+ ```
116
+
117
+ ### 2) Use the Unreal scene component
118
+
119
+ Import the component into a standalone component and use it in the template.
120
+
121
+ ```ts
122
+ import { Component } from '@angular/core';
123
+ import { UnrealSceneComponent } from '@3dsource/angular-unreal-module';
124
+
125
+ @Component({
126
+ selector: 'app-root',
127
+ standalone: true,
128
+ imports: [UnrealSceneComponent],
129
+ template: ` <app-unreal-scene [isStudio]="false" [useContainerAsSizeProvider]="true" [studioResolutionSize]="{ width: 1920, height: 1080 }" (changeMouseOverScene)="onHover($event)"> </app-unreal-scene> `,
130
+ })
131
+ export class AppComponent {
132
+ onHover(isOver: boolean) {
133
+ // handle mouse over scene
134
+ }
135
+ }
136
+ ```
137
+
138
+ Component selector: `<app-unreal-scene>`
139
+
140
+ Inputs:
141
+
142
+ | Input | Type | Default |
143
+ | ---------------------------- | ----------------------------------- | ------------------------------- |
144
+ | `isStudio` | `boolean` | `false` |
145
+ | `useContainerAsSizeProvider` | `boolean` | `true` |
146
+ | `studioResolutionSize` | `{ width: number; height: number }` | `{ width: 1920, height: 1080 }` |
147
+
148
+ Outputs:
149
+
150
+ | Output | Type |
151
+ | ---------------------- | --------------------------- |
152
+ | `changeMouseOverScene` | `OutputEmitterRef<boolean>` |
153
+
154
+ ### 3) Send commands / interactions to Unreal
155
+
156
+ Inject `UnrealCommunicatorService` to send commands or UI interactions. Types for command packets are provided by `@3dsource/types-unreal`.
157
+
158
+ There are three sending methods — choose based on your needs:
159
+
160
+ | Method | Description |
161
+ | --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
162
+ | `sendCommandToUnreal` | Full pipeline: adds `correlationId`, records telemetry, dispatches NgRx `commandStarted` action. **Recommended for application commands.** |
163
+ | `emitUIInteraction` | Sends the packet as a raw `UIInteraction` message. No telemetry or store dispatch. |
164
+ | `emitCommand` | Sends the packet as a raw `Command` message (for console commands, resolution changes, etc.). |
165
+
166
+ ```ts
167
+ import { Component, inject } from '@angular/core';
168
+ import { UnrealCommunicatorService } from '@3dsource/angular-unreal-module';
169
+ import { MetaBoxCommand } from '@3dsource/types-unreal';
170
+ import type { MetaBoxCommandPacket } from '@3dsource/types-unreal';
171
+
172
+ @Component({ standalone: true, template: '' })
173
+ export class MyComponent {
174
+ private unreal = inject(UnrealCommunicatorService);
175
+
176
+ sendSomeCommand() {
177
+ // Recommended: use sendCommandToUnreal for full telemetry + store tracking
178
+ this.unreal.sendCommandToUnreal({
179
+ command: MetaBoxCommand.FChangeResolutionCommand,
180
+ payload: { resolution: { x: 1920, y: 1080 } },
181
+ });
182
+ }
183
+
184
+ sendRawUIInteraction() {
185
+ // Low-level: sends UIInteraction message without telemetry tracking
186
+ const packet = {
187
+ command: 'CustomCommand',
188
+ payload: { key: 'value' },
189
+ } as MetaBoxCommandPacket;
190
+ this.unreal.emitUIInteraction(packet);
191
+ }
192
+ }
193
+ ```
194
+
195
+ ### 4) Store integration (actions & selectors)
196
+
197
+ The module registers an NgRx feature state `commandsFeature`. You can dispatch actions and select state in your components:
198
+
199
+ ```ts
200
+ import { inject } from '@angular/core';
201
+ import { Store } from '@ngrx/store';
202
+ import { startStream, setConfig, setOrchestrationContext, disconnectStream, selectTotalProgress, selectShowLoader, commandsFeature } from '@3dsource/angular-unreal-module';
203
+
204
+ // Dispatch actions
205
+ const store = inject(Store);
206
+ store.dispatch(startStream({ config: { autoStart: true, warnTimeout: 120 } }));
207
+
208
+ // Select state
209
+ const progress = store.selectSignal(selectTotalProgress);
210
+ const isVideoPlaying = store.selectSignal(commandsFeature.selectIsVideoPlaying);
211
+ const dataChannelConnected = store.selectSignal(commandsFeature.selectDataChannelConnected);
212
+ ```
213
+
214
+ **Key selectors:**
215
+
216
+ - `selectTotalProgress` — Scene load progress (0–1 float)
217
+ - `selectShowLoader` — Whether loader screen should be visible
218
+ - `selectShowReconnectPopup` — Whether reconnect popup should be shown
219
+ - `selectIsVideoPlayingAndDataChannelConnected` — Combined readiness check
220
+ - `selectStreamConfig` — Current stream configuration
221
+ - `commandsFeature.selectCirrusConnected` — Signalling server connection status
222
+ - `commandsFeature.selectDataChannelConnected` — Data channel status
223
+ - `commandsFeature.selectViewportReady` — Viewport readiness
224
+
225
+ **Key actions:**
226
+
227
+ - `startStream` — Start streaming with config
228
+ - `setConfig` — Update stream configuration
229
+ - `setOrchestrationContext` — Set orchestration URLs and environment
230
+ - `disconnectStream` — Disconnect with reason
231
+ - `destroyUnrealScene` — Full teardown
232
+ - `reconnectPeer` — Trigger peer reconnection
233
+
234
+ ### 5) Listen for Unreal callbacks
235
+
236
+ Inject `UnrealCallbackService` to listen for callback events from Unreal Engine and to observe command responses.
237
+
238
+ There are two methods:
239
+
240
+ | Method | Description |
241
+ | ------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
242
+ | `fromUnrealCallback` | Listens for callbacks matching a command or event key. Supports MetaBox commands and custom Unreal callback events. Returns `Observable<UnrealCallbackDescriptor[K]>`. |
243
+ | `observeCommandResponse` | Sends a command and waits for its matching response by `correlationId`. Returns `Observable<MetaBoxCommandList[K]>`. Includes timeout and error handling. |
244
+
245
+ **Custom Unreal callback events** (defined in `UnrealCallbackEventMap`):
246
+
247
+ | Event | Payload Type |
248
+ | -------------------------- | --------------------------------------------------- |
249
+ | `onSceneState` | `FSceneState` |
250
+ | `onFocusObject` | `FProductPayload` |
251
+ | `cameraChanged` | `FCameraChangedPayload` |
252
+ | `onObjectTransformChanged` | `{ objectName: string; transform: FTransformJson }` |
253
+ | `onChangeSequence` | `unknown` |
254
+ | `onFinishedSequence` | `unknown` |
255
+
256
+ ```ts
257
+ import { Component, inject } from '@angular/core';
258
+ import { UnrealCallbackService } from '@3dsource/angular-unreal-module';
259
+ import { UnrealCommunicatorService } from '@3dsource/angular-unreal-module';
260
+ import { MetaBoxCommand } from '@3dsource/types-unreal';
261
+
262
+ @Component({ standalone: true, template: '' })
263
+ export class MyComponent {
264
+ private callbackService = inject(UnrealCallbackService);
265
+ private communicator = inject(UnrealCommunicatorService);
266
+
267
+ listenForCallbacks() {
268
+ // Listen for a MetaBox command callback
269
+ this.callbackService.fromUnrealCallback(MetaBoxCommand.FLoadProductCommand).subscribe((data) => console.log('Product loaded:', data));
270
+
271
+ // Listen for a custom Unreal event
272
+ this.callbackService.fromUnrealCallback('cameraChanged').subscribe((data) => console.log('Camera changed:', data));
273
+ }
274
+
275
+ sendAndObserve() {
276
+ // Send a command and observe its response (with correlationId matching)
277
+ this.callbackService
278
+ .observeCommandResponse(
279
+ { command: MetaBoxCommand.FLoopBackCommand },
280
+ (data) => this.communicator.sendCommandToUnreal(data),
281
+ 60000, // timeout in ms (default: 60000)
282
+ true, // emit on timeout (default: true)
283
+ )
284
+ .subscribe((response) => console.log('Response:', response));
285
+ }
286
+ }
287
+ ```
288
+
289
+ ## Exported API
290
+
291
+ ### Components
292
+
293
+ | Component | Selector | Description |
294
+ | -------------------------------- | ------------------ | -------------------------------------- |
295
+ | `UnrealSceneComponent` | `app-unreal-scene` | Main scene container with video stream |
296
+ | `AfkTimeoutModalComponent` | — | AFK timeout warning modal |
297
+ | `FreezeFrameComponent` | — | Freeze frame overlay |
298
+ | `LowBandwidthModalComponent` | — | Low bandwidth warning modal |
299
+ | `LowBandwidthIndicatorComponent` | — | Low bandwidth indicator |
300
+ | `ImageLoadingSrcComponent` | — | Loading image overlay |
301
+ | `IntroSrcComponent` | — | Intro image/video overlay |
302
+ | `VideoStatsComponent` | — | Video statistics display |
303
+ | `StatGraphComponent` | — | Statistics graph |
304
+ | `WebrtcErrorModalComponent` | — | WebRTC error modal |
305
+
306
+ ### Services
307
+
308
+ | Service | Description |
309
+ | ------------------------------ | --------------------------------------------------------------- |
310
+ | `UnrealCommunicatorService` | Send commands and UI interactions to Unreal |
311
+ | `UnrealCallbackService` | Listen for Unreal callback events and observe command responses |
312
+ | `AggregatorService` | Aggregates data channel messages from Unreal |
313
+ | `SignallingService` | Manages WebSocket signalling connection |
314
+ | `VideoService` | Manages video element and stats |
315
+ | `WebRtcPlayerService` | Manages WebRTC peer connection |
316
+ | `FreezeFrameService` | Handles freeze frame images |
317
+ | `AFKService` | AFK (away from keyboard) detection and timeout |
318
+ | `DevModeService` | Toggle dev mode for debugging |
319
+ | `FileReceiverService` | Receives files from Unreal via data channel |
320
+ | `FileHandlerService` | Processes received files |
321
+ | `RegionsPingService` | Pings regions to determine latency |
322
+ | `CommandTelemetryService` | Records command telemetry |
323
+ | `StreamStatusTelemetryService` | Reports stream status telemetry |
324
+ | `AnalyticsService` | Analytics event tracking |
325
+ | `FpsMonitorService` | FPS monitoring |
326
+
327
+ ### Pipes
328
+
329
+ | Pipe | Description |
330
+ | -------------- | ------------------------------- |
331
+ | `SafeHtmlPipe` | Bypasses Angular HTML sanitizer |
332
+
333
+ ### Interfaces
334
+
335
+ | Interface | Description |
336
+ | -------------------------- | ---------------------------------------------------------------------------- |
337
+ | `UnrealInitialConfig` | Shape for `UNREAL_CONFIG` injection token |
338
+ | `ReconnectConfig` | Auto-reconnection behavior configuration |
339
+ | `StreamConfig` | Stream configuration (autoStart, warnTimeout) |
340
+ | `StreamResolutionProps` | Stream resolution width/height |
341
+ | `UnrealCallbackEventMap` | Custom Unreal callback events pushed from Unreal via data channel |
342
+ | `UnrealCallbackDescriptor` | Combined map of MetaBoxCommandList and UnrealCallbackEventMap callback types |
343
+
344
+ ## Features
345
+
346
+ - Standalone Unreal Scene Component
347
+ - Command and UI Interaction API via `UnrealCommunicatorService`
348
+ - Callback listener and command response observer via `UnrealCallbackService`
349
+ - Event-driven status UI (freeze frame, video stats, play overlay, AFK, low bandwidth)
350
+ - NgRx-powered state management and effects
351
+ - **Required** initial configuration via `UNREAL_CONFIG` injection token
352
+ - Auto-reconnection on WebRTC/DataChannel failures (configurable)
353
+ - File receiving from Unreal Engine via data channel
354
+ - Analytics and FPS monitoring
355
+ - Playwright testing mode with mock service substitution
356
+
357
+ ## Examples
358
+
359
+ Check the demo application for complete usage examples:
360
+
361
+ ```shell
362
+ npm run demo:start
363
+ ```
364
+
365
+ See also: `projects/demo/src/app/demo-layout/info-pages/unreal-scene-demo/constants/unreal.routes.ts` for a real-world provider configuration example.
366
+
367
+ ## Engine requirements
368
+
369
+ - Node.js: >=20
370
+ - npm: >9