@3dsource/angular-unreal-module 0.0.125 → 0.0.128

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,369 +1,369 @@
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 { provideAngularUnrealModule, 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
- // Unreal providers (adds feature state and effects internally)
101
- // Tip: pass { playwright: true } to switch to testing/dummy services
102
- provideAngularUnrealModule({ playwright: false }),
103
- ],
104
- };
105
- ```
106
-
107
- #### Minimal configuration
108
-
109
- If you don't need custom endpoints, provide `UNREAL_CONFIG` with an empty object:
110
-
111
- ```ts
112
- { provide: UNREAL_CONFIG, useValue: {} },
113
- provideAngularUnrealModule(),
114
- ```
115
-
116
- ### 2) Use the Unreal scene component
117
-
118
- Import the component into a standalone component and use it in the template.
119
-
120
- ```ts
121
- import { Component } from '@angular/core';
122
- import { UnrealSceneComponent } from '@3dsource/angular-unreal-module';
123
-
124
- @Component({
125
- selector: 'app-root',
126
- standalone: true,
127
- imports: [UnrealSceneComponent],
128
- template: ` <app-unreal-scene [isStudio]="false" [useContainerAsSizeProvider]="true" [studioResolutionSize]="{ width: 1920, height: 1080 }" (changeMouseOverScene)="onHover($event)"> </app-unreal-scene> `,
129
- })
130
- export class AppComponent {
131
- onHover(isOver: boolean) {
132
- // handle mouse over scene
133
- }
134
- }
135
- ```
136
-
137
- Component selector: `<app-unreal-scene>`
138
-
139
- Inputs:
140
-
141
- | Input | Type | Default |
142
- | ---------------------------- | ----------------------------------- | ------------------------------- |
143
- | `isStudio` | `boolean` | `false` |
144
- | `useContainerAsSizeProvider` | `boolean` | `true` |
145
- | `studioResolutionSize` | `{ width: number; height: number }` | `{ width: 1920, height: 1080 }` |
146
-
147
- Outputs:
148
-
149
- | Output | Type |
150
- | ---------------------- | --------------------------- |
151
- | `changeMouseOverScene` | `OutputEmitterRef<boolean>` |
152
-
153
- ### 3) Send commands / interactions to Unreal
154
-
155
- Inject `UnrealCommunicatorService` to send commands or UI interactions. Types for command packets are provided by `@3dsource/types-unreal`.
156
-
157
- There are three sending methods — choose based on your needs:
158
-
159
- | Method | Description |
160
- | --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
161
- | `sendCommandToUnreal` | Full pipeline: adds `correlationId`, records telemetry, dispatches NgRx `commandStarted` action. **Recommended for application commands.** |
162
- | `emitUIInteraction` | Sends the packet as a raw `UIInteraction` message. No telemetry or store dispatch. |
163
- | `emitCommand` | Sends the packet as a raw `Command` message (for console commands, resolution changes, etc.). |
164
-
165
- ```ts
166
- import { Component, inject } from '@angular/core';
167
- import { UnrealCommunicatorService } from '@3dsource/angular-unreal-module';
168
- import { MetaBoxCommand } from '@3dsource/types-unreal';
169
- import type { MetaBoxCommandPacket } from '@3dsource/types-unreal';
170
-
171
- @Component({ standalone: true, template: '' })
172
- export class MyComponent {
173
- private unreal = inject(UnrealCommunicatorService);
174
-
175
- sendSomeCommand() {
176
- // Recommended: use sendCommandToUnreal for full telemetry + store tracking
177
- this.unreal.sendCommandToUnreal({
178
- command: MetaBoxCommand.FChangeResolutionCommand,
179
- payload: { resolution: { x: 1920, y: 1080 } },
180
- });
181
- }
182
-
183
- sendRawUIInteraction() {
184
- // Low-level: sends UIInteraction message without telemetry tracking
185
- const packet = {
186
- command: 'CustomCommand',
187
- payload: { key: 'value' },
188
- } as MetaBoxCommandPacket;
189
- this.unreal.emitUIInteraction(packet);
190
- }
191
- }
192
- ```
193
-
194
- ### 4) Store integration (actions & selectors)
195
-
196
- The module registers an NgRx feature state `commandsFeature`. You can dispatch actions and select state in your components:
197
-
198
- ```ts
199
- import { inject } from '@angular/core';
200
- import { Store } from '@ngrx/store';
201
- import { startStream, setConfig, setOrchestrationContext, disconnectStream, selectTotalProgress, selectShowLoader, commandsFeature } from '@3dsource/angular-unreal-module';
202
-
203
- // Dispatch actions
204
- const store = inject(Store);
205
- store.dispatch(startStream({ config: { autoStart: true, warnTimeout: 120 } }));
206
-
207
- // Select state
208
- const progress = store.selectSignal(selectTotalProgress);
209
- const isVideoPlaying = store.selectSignal(commandsFeature.selectIsVideoPlaying);
210
- const dataChannelConnected = store.selectSignal(commandsFeature.selectDataChannelConnected);
211
- ```
212
-
213
- **Key selectors:**
214
-
215
- - `selectTotalProgress` — Scene load progress (0–1 float)
216
- - `selectShowLoader` — Whether loader screen should be visible
217
- - `selectShowReconnectPopup` — Whether reconnect popup should be shown
218
- - `selectIsVideoPlayingAndDataChannelConnected` — Combined readiness check
219
- - `selectStreamConfig` — Current stream configuration
220
- - `commandsFeature.selectCirrusConnected` — Signalling server connection status
221
- - `commandsFeature.selectDataChannelConnected` — Data channel status
222
- - `commandsFeature.selectViewportReady` — Viewport readiness
223
-
224
- **Key actions:**
225
-
226
- - `startStream` — Start streaming with config
227
- - `setConfig` — Update stream configuration
228
- - `setOrchestrationContext` — Set orchestration URLs and environment
229
- - `disconnectStream` — Disconnect with reason
230
- - `destroyUnrealScene` — Full teardown
231
- - `reconnectPeer` — Trigger peer reconnection
232
-
233
- ### 5) Listen for Unreal callbacks
234
-
235
- Inject `UnrealCallbackService` to listen for callback events from Unreal Engine and to observe command responses.
236
-
237
- There are two methods:
238
-
239
- | Method | Description |
240
- | ------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
241
- | `fromUnrealCallback` | Listens for callbacks matching a command or event key. Supports MetaBox commands and custom Unreal callback events. Returns `Observable<UnrealCallbackDescriptor[K]>`. |
242
- | `observeCommandResponse` | Sends a command and waits for its matching response by `correlationId`. Returns `Observable<MetaBoxCommandList[K]>`. Includes timeout and error handling. |
243
-
244
- **Custom Unreal callback events** (defined in `UnrealCallbackEventMap`):
245
-
246
- | Event | Payload Type |
247
- | -------------------------- | --------------------------------------------------- |
248
- | `onSceneState` | `FSceneState` |
249
- | `onFocusObject` | `FProductPayload` |
250
- | `cameraChanged` | `FCameraChangedPayload` |
251
- | `onObjectTransformChanged` | `{ objectName: string; transform: FTransformJson }` |
252
- | `onChangeSequence` | `unknown` |
253
- | `onFinishedSequence` | `unknown` |
254
-
255
- ```ts
256
- import { Component, inject } from '@angular/core';
257
- import { UnrealCallbackService } from '@3dsource/angular-unreal-module';
258
- import { UnrealCommunicatorService } from '@3dsource/angular-unreal-module';
259
- import { MetaBoxCommand } from '@3dsource/types-unreal';
260
-
261
- @Component({ standalone: true, template: '' })
262
- export class MyComponent {
263
- private callbackService = inject(UnrealCallbackService);
264
- private communicator = inject(UnrealCommunicatorService);
265
-
266
- listenForCallbacks() {
267
- // Listen for a MetaBox command callback
268
- this.callbackService.fromUnrealCallback(MetaBoxCommand.FLoadProductCommand).subscribe((data) => console.log('Product loaded:', data));
269
-
270
- // Listen for a custom Unreal event
271
- this.callbackService.fromUnrealCallback('cameraChanged').subscribe((data) => console.log('Camera changed:', data));
272
- }
273
-
274
- sendAndObserve() {
275
- // Send a command and observe its response (with correlationId matching)
276
- this.callbackService
277
- .observeCommandResponse(
278
- { command: MetaBoxCommand.FLoopBackCommand },
279
- (data) => this.communicator.sendCommandToUnreal(data),
280
- 60000, // timeout in ms (default: 60000)
281
- true, // emit on timeout (default: true)
282
- )
283
- .subscribe((response) => console.log('Response:', response));
284
- }
285
- }
286
- ```
287
-
288
- ## Exported API
289
-
290
- ### Components
291
-
292
- | Component | Selector | Description |
293
- | -------------------------------- | ------------------ | -------------------------------------- |
294
- | `UnrealSceneComponent` | `app-unreal-scene` | Main scene container with video stream |
295
- | `AfkTimeoutModalComponent` | — | AFK timeout warning modal |
296
- | `FreezeFrameComponent` | — | Freeze frame overlay |
297
- | `LowBandwidthModalComponent` | — | Low bandwidth warning modal |
298
- | `LowBandwidthIndicatorComponent` | — | Low bandwidth indicator |
299
- | `ImageLoadingSrcComponent` | — | Loading image overlay |
300
- | `IntroSrcComponent` | — | Intro image/video overlay |
301
- | `VideoStatsComponent` | — | Video statistics display |
302
- | `StatGraphComponent` | — | Statistics graph |
303
- | `WebrtcErrorModalComponent` | — | WebRTC error modal |
304
-
305
- ### Services
306
-
307
- | Service | Description |
308
- | ------------------------------ | --------------------------------------------------------------- |
309
- | `UnrealCommunicatorService` | Send commands and UI interactions to Unreal |
310
- | `UnrealCallbackService` | Listen for Unreal callback events and observe command responses |
311
- | `AggregatorService` | Aggregates data channel messages from Unreal |
312
- | `SignallingService` | Manages WebSocket signalling connection |
313
- | `VideoService` | Manages video element and stats |
314
- | `WebRtcPlayerService` | Manages WebRTC peer connection |
315
- | `FreezeFrameService` | Handles freeze frame images |
316
- | `AFKService` | AFK (away from keyboard) detection and timeout |
317
- | `DevModeService` | Toggle dev mode for debugging |
318
- | `FileReceiverService` | Receives files from Unreal via data channel |
319
- | `FileHandlerService` | Processes received files |
320
- | `RegionsPingService` | Pings regions to determine latency |
321
- | `CommandTelemetryService` | Records command telemetry |
322
- | `StreamStatusTelemetryService` | Reports stream status telemetry |
323
- | `AnalyticsService` | Analytics event tracking |
324
- | `FpsMonitorService` | FPS monitoring |
325
-
326
- ### Pipes
327
-
328
- | Pipe | Description |
329
- | -------------- | ------------------------------- |
330
- | `SafeHtmlPipe` | Bypasses Angular HTML sanitizer |
331
-
332
- ### Interfaces
333
-
334
- | Interface | Description |
335
- | -------------------------- | ---------------------------------------------------------------------------- |
336
- | `UnrealInitialConfig` | Shape for `UNREAL_CONFIG` injection token |
337
- | `ReconnectConfig` | Auto-reconnection behavior configuration |
338
- | `StreamConfig` | Stream configuration (autoStart, warnTimeout) |
339
- | `StreamResolutionProps` | Stream resolution width/height |
340
- | `UnrealCallbackEventMap` | Custom Unreal callback events pushed from Unreal via data channel |
341
- | `UnrealCallbackDescriptor` | Combined map of MetaBoxCommandList and UnrealCallbackEventMap callback types |
342
-
343
- ## Features
344
-
345
- - Standalone Unreal Scene Component
346
- - Command and UI Interaction API via `UnrealCommunicatorService`
347
- - Callback listener and command response observer via `UnrealCallbackService`
348
- - Event-driven status UI (freeze frame, video stats, play overlay, AFK, low bandwidth)
349
- - NgRx-powered state management and effects
350
- - **Required** initial configuration via `UNREAL_CONFIG` injection token
351
- - Auto-reconnection on WebRTC/DataChannel failures (configurable)
352
- - File receiving from Unreal Engine via data channel
353
- - Analytics and FPS monitoring
354
- - Playwright testing mode with mock service substitution
355
-
356
- ## Examples
357
-
358
- Check the demo application for complete usage examples:
359
-
360
- ```shell
361
- npm run demo:start
362
- ```
363
-
364
- See also: `projects/demo/src/app/demo-layout/info-pages/unreal-scene-demo/constants/unreal.routes.ts` for a real-world provider configuration example.
365
-
366
- ## Engine requirements
367
-
368
- - Node.js: >=20
369
- - 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 { provideAngularUnrealModule, 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
+ // Unreal providers (adds feature state and effects internally)
101
+ // Tip: pass { playwright: true } to switch to testing/dummy services
102
+ provideAngularUnrealModule({ playwright: false }),
103
+ ],
104
+ };
105
+ ```
106
+
107
+ #### Minimal configuration
108
+
109
+ If you don't need custom endpoints, provide `UNREAL_CONFIG` with an empty object:
110
+
111
+ ```ts
112
+ { provide: UNREAL_CONFIG, useValue: {} },
113
+ provideAngularUnrealModule(),
114
+ ```
115
+
116
+ ### 2) Use the Unreal scene component
117
+
118
+ Import the component into a standalone component and use it in the template.
119
+
120
+ ```ts
121
+ import { Component } from '@angular/core';
122
+ import { UnrealSceneComponent } from '@3dsource/angular-unreal-module';
123
+
124
+ @Component({
125
+ selector: 'app-root',
126
+ standalone: true,
127
+ imports: [UnrealSceneComponent],
128
+ template: ` <app-unreal-scene [isStudio]="false" [useContainerAsSizeProvider]="true" [studioResolutionSize]="{ width: 1920, height: 1080 }" (changeMouseOverScene)="onHover($event)"> </app-unreal-scene> `,
129
+ })
130
+ export class AppComponent {
131
+ onHover(isOver: boolean) {
132
+ // handle mouse over scene
133
+ }
134
+ }
135
+ ```
136
+
137
+ Component selector: `<app-unreal-scene>`
138
+
139
+ Inputs:
140
+
141
+ | Input | Type | Default |
142
+ | ---------------------------- | ----------------------------------- | ------------------------------- |
143
+ | `isStudio` | `boolean` | `false` |
144
+ | `useContainerAsSizeProvider` | `boolean` | `true` |
145
+ | `studioResolutionSize` | `{ width: number; height: number }` | `{ width: 1920, height: 1080 }` |
146
+
147
+ Outputs:
148
+
149
+ | Output | Type |
150
+ | ---------------------- | --------------------------- |
151
+ | `changeMouseOverScene` | `OutputEmitterRef<boolean>` |
152
+
153
+ ### 3) Send commands / interactions to Unreal
154
+
155
+ Inject `UnrealCommunicatorService` to send commands or UI interactions. Types for command packets are provided by `@3dsource/types-unreal`.
156
+
157
+ There are three sending methods — choose based on your needs:
158
+
159
+ | Method | Description |
160
+ | --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
161
+ | `sendCommandToUnreal` | Full pipeline: adds `correlationId`, records telemetry, dispatches NgRx `commandStarted` action. **Recommended for application commands.** |
162
+ | `emitUIInteraction` | Sends the packet as a raw `UIInteraction` message. No telemetry or store dispatch. |
163
+ | `emitCommand` | Sends the packet as a raw `Command` message (for console commands, resolution changes, etc.). |
164
+
165
+ ```ts
166
+ import { Component, inject } from '@angular/core';
167
+ import { UnrealCommunicatorService } from '@3dsource/angular-unreal-module';
168
+ import { MetaBoxCommand } from '@3dsource/types-unreal';
169
+ import type { MetaBoxCommandPacket } from '@3dsource/types-unreal';
170
+
171
+ @Component({ standalone: true, template: '' })
172
+ export class MyComponent {
173
+ private unreal = inject(UnrealCommunicatorService);
174
+
175
+ sendSomeCommand() {
176
+ // Recommended: use sendCommandToUnreal for full telemetry + store tracking
177
+ this.unreal.sendCommandToUnreal({
178
+ command: MetaBoxCommand.FChangeResolutionCommand,
179
+ payload: { resolution: { x: 1920, y: 1080 } },
180
+ });
181
+ }
182
+
183
+ sendRawUIInteraction() {
184
+ // Low-level: sends UIInteraction message without telemetry tracking
185
+ const packet = {
186
+ command: 'CustomCommand',
187
+ payload: { key: 'value' },
188
+ } as MetaBoxCommandPacket;
189
+ this.unreal.emitUIInteraction(packet);
190
+ }
191
+ }
192
+ ```
193
+
194
+ ### 4) Store integration (actions & selectors)
195
+
196
+ The module registers an NgRx feature state `commandsFeature`. You can dispatch actions and select state in your components:
197
+
198
+ ```ts
199
+ import { inject } from '@angular/core';
200
+ import { Store } from '@ngrx/store';
201
+ import { startStream, setConfig, setOrchestrationContext, disconnectStream, selectTotalProgress, selectShowLoader, commandsFeature } from '@3dsource/angular-unreal-module';
202
+
203
+ // Dispatch actions
204
+ const store = inject(Store);
205
+ store.dispatch(startStream({ config: { autoStart: true, warnTimeout: 120 } }));
206
+
207
+ // Select state
208
+ const progress = store.selectSignal(selectTotalProgress);
209
+ const isVideoPlaying = store.selectSignal(commandsFeature.selectIsVideoPlaying);
210
+ const dataChannelConnected = store.selectSignal(commandsFeature.selectDataChannelConnected);
211
+ ```
212
+
213
+ **Key selectors:**
214
+
215
+ - `selectTotalProgress` — Scene load progress (0–1 float)
216
+ - `selectShowLoader` — Whether loader screen should be visible
217
+ - `selectShowReconnectPopup` — Whether reconnect popup should be shown
218
+ - `selectIsVideoPlayingAndDataChannelConnected` — Combined readiness check
219
+ - `selectStreamConfig` — Current stream configuration
220
+ - `commandsFeature.selectCirrusConnected` — Signalling server connection status
221
+ - `commandsFeature.selectDataChannelConnected` — Data channel status
222
+ - `commandsFeature.selectViewportReady` — Viewport readiness
223
+
224
+ **Key actions:**
225
+
226
+ - `startStream` — Start streaming with config
227
+ - `setConfig` — Update stream configuration
228
+ - `setOrchestrationContext` — Set orchestration URLs and environment
229
+ - `disconnectStream` — Disconnect with reason
230
+ - `destroyUnrealScene` — Full teardown
231
+ - `reconnectPeer` — Trigger peer reconnection
232
+
233
+ ### 5) Listen for Unreal callbacks
234
+
235
+ Inject `UnrealCallbackService` to listen for callback events from Unreal Engine and to observe command responses.
236
+
237
+ There are two methods:
238
+
239
+ | Method | Description |
240
+ | ------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
241
+ | `fromUnrealCallback` | Listens for callbacks matching a command or event key. Supports MetaBox commands and custom Unreal callback events. Returns `Observable<UnrealCallbackDescriptor[K]>`. |
242
+ | `observeCommandResponse` | Sends a command and waits for its matching response by `correlationId`. Returns `Observable<MetaBoxCommandList[K]>`. Includes timeout and error handling. |
243
+
244
+ **Custom Unreal callback events** (defined in `UnrealCallbackEventMap`):
245
+
246
+ | Event | Payload Type |
247
+ | -------------------------- | --------------------------------------------------- |
248
+ | `onSceneState` | `FSceneState` |
249
+ | `onFocusObject` | `FProductPayload` |
250
+ | `cameraChanged` | `FCameraChangedPayload` |
251
+ | `onObjectTransformChanged` | `{ objectName: string; transform: FTransformJson }` |
252
+ | `onChangeSequence` | `unknown` |
253
+ | `onFinishedSequence` | `unknown` |
254
+
255
+ ```ts
256
+ import { Component, inject } from '@angular/core';
257
+ import { UnrealCallbackService } from '@3dsource/angular-unreal-module';
258
+ import { UnrealCommunicatorService } from '@3dsource/angular-unreal-module';
259
+ import { MetaBoxCommand } from '@3dsource/types-unreal';
260
+
261
+ @Component({ standalone: true, template: '' })
262
+ export class MyComponent {
263
+ private callbackService = inject(UnrealCallbackService);
264
+ private communicator = inject(UnrealCommunicatorService);
265
+
266
+ listenForCallbacks() {
267
+ // Listen for a MetaBox command callback
268
+ this.callbackService.fromUnrealCallback(MetaBoxCommand.FLoadProductCommand).subscribe((data) => console.log('Product loaded:', data));
269
+
270
+ // Listen for a custom Unreal event
271
+ this.callbackService.fromUnrealCallback('cameraChanged').subscribe((data) => console.log('Camera changed:', data));
272
+ }
273
+
274
+ sendAndObserve() {
275
+ // Send a command and observe its response (with correlationId matching)
276
+ this.callbackService
277
+ .observeCommandResponse(
278
+ { command: MetaBoxCommand.FLoopBackCommand },
279
+ (data) => this.communicator.sendCommandToUnreal(data),
280
+ 60000, // timeout in ms (default: 60000)
281
+ true, // emit on timeout (default: true)
282
+ )
283
+ .subscribe((response) => console.log('Response:', response));
284
+ }
285
+ }
286
+ ```
287
+
288
+ ## Exported API
289
+
290
+ ### Components
291
+
292
+ | Component | Selector | Description |
293
+ | -------------------------------- | ------------------ | -------------------------------------- |
294
+ | `UnrealSceneComponent` | `app-unreal-scene` | Main scene container with video stream |
295
+ | `AfkTimeoutModalComponent` | — | AFK timeout warning modal |
296
+ | `FreezeFrameComponent` | — | Freeze frame overlay |
297
+ | `LowBandwidthModalComponent` | — | Low bandwidth warning modal |
298
+ | `LowBandwidthIndicatorComponent` | — | Low bandwidth indicator |
299
+ | `ImageLoadingSrcComponent` | — | Loading image overlay |
300
+ | `IntroSrcComponent` | — | Intro image/video overlay |
301
+ | `VideoStatsComponent` | — | Video statistics display |
302
+ | `StatGraphComponent` | — | Statistics graph |
303
+ | `WebrtcErrorModalComponent` | — | WebRTC error modal |
304
+
305
+ ### Services
306
+
307
+ | Service | Description |
308
+ | ------------------------------ | --------------------------------------------------------------- |
309
+ | `UnrealCommunicatorService` | Send commands and UI interactions to Unreal |
310
+ | `UnrealCallbackService` | Listen for Unreal callback events and observe command responses |
311
+ | `AggregatorService` | Aggregates data channel messages from Unreal |
312
+ | `SignallingService` | Manages WebSocket signalling connection |
313
+ | `VideoService` | Manages video element and stats |
314
+ | `WebRtcPlayerService` | Manages WebRTC peer connection |
315
+ | `FreezeFrameService` | Handles freeze frame images |
316
+ | `AFKService` | AFK (away from keyboard) detection and timeout |
317
+ | `DevModeService` | Toggle dev mode for debugging |
318
+ | `FileReceiverService` | Receives files from Unreal via data channel |
319
+ | `FileHandlerService` | Processes received files |
320
+ | `RegionsPingService` | Pings regions to determine latency |
321
+ | `CommandTelemetryService` | Records command telemetry |
322
+ | `StreamStatusTelemetryService` | Reports stream status telemetry |
323
+ | `AnalyticsService` | Analytics event tracking |
324
+ | `FpsMonitorService` | FPS monitoring |
325
+
326
+ ### Pipes
327
+
328
+ | Pipe | Description |
329
+ | -------------- | ------------------------------- |
330
+ | `SafeHtmlPipe` | Bypasses Angular HTML sanitizer |
331
+
332
+ ### Interfaces
333
+
334
+ | Interface | Description |
335
+ | -------------------------- | ---------------------------------------------------------------------------- |
336
+ | `UnrealInitialConfig` | Shape for `UNREAL_CONFIG` injection token |
337
+ | `ReconnectConfig` | Auto-reconnection behavior configuration |
338
+ | `StreamConfig` | Stream configuration (autoStart, warnTimeout) |
339
+ | `StreamResolutionProps` | Stream resolution width/height |
340
+ | `UnrealCallbackEventMap` | Custom Unreal callback events pushed from Unreal via data channel |
341
+ | `UnrealCallbackDescriptor` | Combined map of MetaBoxCommandList and UnrealCallbackEventMap callback types |
342
+
343
+ ## Features
344
+
345
+ - Standalone Unreal Scene Component
346
+ - Command and UI Interaction API via `UnrealCommunicatorService`
347
+ - Callback listener and command response observer via `UnrealCallbackService`
348
+ - Event-driven status UI (freeze frame, video stats, play overlay, AFK, low bandwidth)
349
+ - NgRx-powered state management and effects
350
+ - **Required** initial configuration via `UNREAL_CONFIG` injection token
351
+ - Auto-reconnection on WebRTC/DataChannel failures (configurable)
352
+ - File receiving from Unreal Engine via data channel
353
+ - Analytics and FPS monitoring
354
+ - Playwright testing mode with mock service substitution
355
+
356
+ ## Examples
357
+
358
+ Check the demo application for complete usage examples:
359
+
360
+ ```shell
361
+ npm run demo:start
362
+ ```
363
+
364
+ See also: `projects/demo/src/app/demo-layout/info-pages/unreal-scene-demo/constants/unreal.routes.ts` for a real-world provider configuration example.
365
+
366
+ ## Engine requirements
367
+
368
+ - Node.js: >=20
369
+ - npm: >9