@3dsource/angular-unreal-module 0.0.156-dev.0 → 0.0.157
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/LICENSE +14 -14
- package/README.md +422 -412
- package/fesm2022/3dsource-angular-unreal-module.mjs +86 -44
- package/fesm2022/3dsource-angular-unreal-module.mjs.map +1 -1
- package/package.json +1 -1
- package/types/3dsource-angular-unreal-module.d.ts +290 -46
package/README.md
CHANGED
|
@@ -1,412 +1,422 @@
|
|
|
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 `>=19.0.0 <23.0.0`
|
|
24
|
-
- NgRx store and effects `>=19.0.0 <23.0.0`
|
|
25
|
-
- Angular CDK `>=19.0.0 <23.0.0` — used for dialog overlays
|
|
26
|
-
- RxJS `>=7.8.0 <8.0.0`
|
|
27
|
-
- `provideHttpClient()` — required by internal services (telemetry, signalling, regions ping, error reporting)
|
|
28
|
-
|
|
29
|
-
### Peer Dependencies
|
|
30
|
-
|
|
31
|
-
This library requires the following peer dependencies:
|
|
32
|
-
|
|
33
|
-
```json
|
|
34
|
-
{
|
|
35
|
-
"@3dsource/source-ui-native": ">=1.0.9",
|
|
36
|
-
"@3dsource/types-unreal": ">=0.0.7",
|
|
37
|
-
"@3dsource/utils": ">=1.0.21",
|
|
38
|
-
"@angular/cdk": ">=19.0.0 <23.0.0",
|
|
39
|
-
"@angular/common": ">=19.0.0 <23.0.0",
|
|
40
|
-
"@angular/core": ">=19.0.0 <23.0.0",
|
|
41
|
-
"@angular/forms": ">=19.0.0 <23.0.0",
|
|
42
|
-
"@angular/platform-browser": ">=19.0.0 <23.0.0",
|
|
43
|
-
"@ngrx/effects": ">=19.0.0 <23.0.0",
|
|
44
|
-
"@ngrx/store": ">=19.0.0 <23.0.0",
|
|
45
|
-
"rxjs": ">=7.8.0 <8.0.0"
|
|
46
|
-
}
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
### Library Installation
|
|
50
|
-
|
|
51
|
-
```shell
|
|
52
|
-
npm i @3dsource/angular-unreal-module
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
## Usage
|
|
56
|
-
|
|
57
|
-
The API is fully standalone (no NgModule). Use providers and components as shown below.
|
|
58
|
-
|
|
59
|
-
### 1) Provide the state and config at the application root
|
|
60
|
-
|
|
61
|
-
Add providers in your application bootstrap (e.g., `app.config.ts`):
|
|
62
|
-
|
|
63
|
-
> **⚠️ 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.
|
|
64
|
-
|
|
65
|
-
```ts
|
|
66
|
-
import { ApplicationConfig } from '@angular/core';
|
|
67
|
-
import { provideRouter } from '@angular/router';
|
|
68
|
-
import { provideHttpClient } from '@angular/common/http';
|
|
69
|
-
import { provideStore } from '@ngrx/store';
|
|
70
|
-
import { provideUnrealState, UNREAL_CONFIG } from '@3dsource/angular-unreal-module';
|
|
71
|
-
|
|
72
|
-
export const appConfig: ApplicationConfig = {
|
|
73
|
-
providers: [
|
|
74
|
-
provideRouter([]),
|
|
75
|
-
provideHttpClient(),
|
|
76
|
-
|
|
77
|
-
// Root NgRx (if not already added in your app)
|
|
78
|
-
provideStore(),
|
|
79
|
-
provideUnrealState(),
|
|
80
|
-
|
|
81
|
-
// Required: Unreal initial configuration
|
|
82
|
-
{
|
|
83
|
-
provide: UNREAL_CONFIG,
|
|
84
|
-
useValue: {
|
|
85
|
-
customErrorsEndpoint: '', // Endpoint for custom error reporting
|
|
86
|
-
commandTelemetryReceiver: '', // Endpoint for command telemetry
|
|
87
|
-
regionsPingUrl: '', // URL prefix for regions latency ping
|
|
88
|
-
screenLockerContainerId: '', // DOM container id for screen locker overlay
|
|
89
|
-
dataChannelConnectionTimeout: 8000, // Timeout in ms for data channel connection (default: 8000)
|
|
90
|
-
streamTelemetryV2Url: '', // Endpoint for stream-status telemetry
|
|
91
|
-
fpsMonitor: false, // Enable FPS monitoring
|
|
92
|
-
autoHighResolution: false, // Raise resolution after the scene becomes idle
|
|
93
|
-
playwright: false, // Mirrors the provider flag for services/effects
|
|
94
|
-
},
|
|
95
|
-
},
|
|
96
|
-
],
|
|
97
|
-
};
|
|
98
|
-
```
|
|
99
|
-
|
|
100
|
-
#### Minimal configuration
|
|
101
|
-
|
|
102
|
-
If you don't need custom endpoints, provide `UNREAL_CONFIG` with an empty object:
|
|
103
|
-
|
|
104
|
-
```ts
|
|
105
|
-
{ provide: UNREAL_CONFIG, useValue: {} },
|
|
106
|
-
provideUnrealState(),
|
|
107
|
-
```
|
|
108
|
-
|
|
109
|
-
Every `UnrealInitialConfig` field is optional, but the `UNREAL_CONFIG` provider
|
|
110
|
-
itself is required. Available fields are `playwright`,
|
|
111
|
-
`customErrorsEndpoint`, `commandTelemetryReceiver`, `regionsPingUrl`,
|
|
112
|
-
`screenLockerContainerId`, `dataChannelConnectionTimeout`,
|
|
113
|
-
`streamTelemetryV2Url`, `fpsMonitor` and `autoHighResolution`.
|
|
114
|
-
|
|
115
|
-
### 2) Boot the engine in each lazy 3D route
|
|
116
|
-
|
|
117
|
-
`provideUnrealModule()` registers the effects and initializes the streaming
|
|
118
|
-
services. Put it on every lazy route that renders a 3D scene:
|
|
119
|
-
|
|
120
|
-
```ts
|
|
121
|
-
import { Routes } from '@angular/router';
|
|
122
|
-
import { provideUnrealModule } from '@3dsource/angular-unreal-module';
|
|
123
|
-
|
|
124
|
-
export const STREAM_ROUTES: Routes = [
|
|
125
|
-
{
|
|
126
|
-
path: ':id',
|
|
127
|
-
loadComponent: () => import('./stream.component').then((module) => module.StreamComponent),
|
|
128
|
-
providers: [provideUnrealModule()],
|
|
129
|
-
},
|
|
130
|
-
];
|
|
131
|
-
```
|
|
132
|
-
|
|
133
|
-
Keep `provideUnrealState()` and `UNREAL_CONFIG` at the root. Keeping
|
|
134
|
-
`provideUnrealModule()` in lazy routes also keeps the streaming engine out of
|
|
135
|
-
the initial application bundle.
|
|
136
|
-
|
|
137
|
-
### 3) Use the Unreal scene component
|
|
138
|
-
|
|
139
|
-
Import the component into a standalone component and use it in the template.
|
|
140
|
-
|
|
141
|
-
```ts
|
|
142
|
-
import { Component } from '@angular/core';
|
|
143
|
-
import { UnrealSceneComponent } from '@3dsource/angular-unreal-module';
|
|
144
|
-
|
|
145
|
-
@Component({
|
|
146
|
-
selector: 'app-root',
|
|
147
|
-
standalone: true,
|
|
148
|
-
imports: [UnrealSceneComponent],
|
|
149
|
-
template: ` <app-unreal-scene [isStudio]="false" [useContainerAsSizeProvider]="true" [resolutionSize]="{ width: 1920, height: 1080 }" (changeMouseOverScene)="onHover($event)" /> `,
|
|
150
|
-
})
|
|
151
|
-
export class AppComponent {
|
|
152
|
-
onHover(isOver: boolean) {
|
|
153
|
-
// handle mouse over scene
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
```
|
|
157
|
-
|
|
158
|
-
Component selector: `<app-unreal-scene>`
|
|
159
|
-
|
|
160
|
-
Inputs:
|
|
161
|
-
|
|
162
|
-
| Input | Type | Default |
|
|
163
|
-
| ---------------------------- | ----------------------------------- | ------------------------------- |
|
|
164
|
-
| `isStudio` | `boolean` | `false` |
|
|
165
|
-
| `useContainerAsSizeProvider` | `boolean` | `true` |
|
|
166
|
-
| `resolutionSize` | `{ width: number; height: number }` | `{ width: 1920, height: 1080 }` |
|
|
167
|
-
|
|
168
|
-
Outputs:
|
|
169
|
-
|
|
170
|
-
| Output | Type |
|
|
171
|
-
| ---------------------- | --------------------------- |
|
|
172
|
-
| `changeMouseOverScene` | `OutputEmitterRef<boolean>` |
|
|
173
|
-
|
|
174
|
-
### 4) Send commands / interactions to Unreal
|
|
175
|
-
|
|
176
|
-
Inject `UnrealCommunicatorService` to send commands or UI interactions. Types for command packets are provided by `@3dsource/types-unreal`.
|
|
177
|
-
|
|
178
|
-
There are three sending methods — choose based on your needs:
|
|
179
|
-
|
|
180
|
-
| Method | Description |
|
|
181
|
-
| --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
182
|
-
| `sendCommandToUnreal` | Full pipeline: adds `correlationId`, records telemetry, dispatches NgRx `commandStarted` action. **Recommended for application commands.** |
|
|
183
|
-
| `emitUIInteraction` | Sends the packet as a raw `UIInteraction` message. No telemetry or store dispatch. |
|
|
184
|
-
| `emitCommand` | Sends the packet as a raw `Command` message (for console commands, resolution changes, etc.). |
|
|
185
|
-
|
|
186
|
-
```ts
|
|
187
|
-
import { Component, inject } from '@angular/core';
|
|
188
|
-
import { UnrealCommunicatorService } from '@3dsource/angular-unreal-module';
|
|
189
|
-
import { MetaBoxCommand } from '@3dsource/types-unreal';
|
|
190
|
-
import type { MetaBoxCommandPacket } from '@3dsource/types-unreal';
|
|
191
|
-
|
|
192
|
-
@Component({ standalone: true, template: '' })
|
|
193
|
-
export class MyComponent {
|
|
194
|
-
private unreal = inject(UnrealCommunicatorService);
|
|
195
|
-
|
|
196
|
-
sendSomeCommand() {
|
|
197
|
-
// Recommended: use sendCommandToUnreal for full telemetry + store tracking
|
|
198
|
-
this.unreal.sendCommandToUnreal({
|
|
199
|
-
command: MetaBoxCommand.FChangeResolutionCommand,
|
|
200
|
-
payload: { resolution: { x: 1920, y: 1080 } },
|
|
201
|
-
});
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
sendRawUIInteraction() {
|
|
205
|
-
// Low-level: sends UIInteraction message without telemetry tracking
|
|
206
|
-
const packet = {
|
|
207
|
-
command: 'CustomCommand',
|
|
208
|
-
payload: { key: 'value' },
|
|
209
|
-
} as MetaBoxCommandPacket;
|
|
210
|
-
this.unreal.emitUIInteraction(packet);
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
```
|
|
214
|
-
|
|
215
|
-
### 5) Store integration (actions & selectors)
|
|
216
|
-
|
|
217
|
-
`provideUnrealState()` registers the NgRx feature state `unrealFeature`. You
|
|
218
|
-
can dispatch actions and select state in your components:
|
|
219
|
-
|
|
220
|
-
```ts
|
|
221
|
-
import { inject } from '@angular/core';
|
|
222
|
-
import { Store } from '@ngrx/store';
|
|
223
|
-
import { disconnectStream, selectShowLoader, selectTotalProgress, setConfig, setOrchestrationContext, startStream, unrealFeature } from '@3dsource/angular-unreal-module';
|
|
224
|
-
|
|
225
|
-
// Dispatch actions
|
|
226
|
-
const store = inject(Store);
|
|
227
|
-
store.dispatch(startStream({ config: { autoStart: true, warnTimeout: 120 } }));
|
|
228
|
-
|
|
229
|
-
// Select state
|
|
230
|
-
const progress = store.selectSignal(selectTotalProgress);
|
|
231
|
-
const isVideoPlaying = store.selectSignal(unrealFeature.selectIsVideoPlaying);
|
|
232
|
-
const dataChannelConnected = store.selectSignal(unrealFeature.selectDataChannelConnected);
|
|
233
|
-
```
|
|
234
|
-
|
|
235
|
-
**Key selectors:**
|
|
236
|
-
|
|
237
|
-
- `selectTotalProgress` — Scene load progress (0–1 float)
|
|
238
|
-
- `selectShowLoader` — Whether loader screen should be visible
|
|
239
|
-
- `selectShowReconnectPopup` — Whether reconnect popup should be shown
|
|
240
|
-
- `selectIsVideoPlayingAndDataChannelConnected` — Combined readiness check
|
|
241
|
-
- `selectStreamConfig` — Current stream configuration
|
|
242
|
-
- `unrealFeature.selectCirrusConnected` — Signalling server connection status
|
|
243
|
-
- `unrealFeature.selectDataChannelConnected` — Data channel status
|
|
244
|
-
- `unrealFeature.selectViewportReady` — Viewport readiness
|
|
245
|
-
|
|
246
|
-
**Key actions:**
|
|
247
|
-
|
|
248
|
-
- `startStream` — Start streaming with config
|
|
249
|
-
- `setConfig` — Update stream configuration
|
|
250
|
-
- `setOrchestrationContext` — Set orchestration URLs and environment
|
|
251
|
-
- `disconnectStream` — Disconnect with reason
|
|
252
|
-
- `destroyUnrealScene` — Full teardown
|
|
253
|
-
- `reconnectPeer` — Trigger peer reconnection
|
|
254
|
-
|
|
255
|
-
### 6) Listen for Unreal callbacks
|
|
256
|
-
|
|
257
|
-
Inject `UnrealCallbackService` to listen for callback events from Unreal Engine and to observe command responses.
|
|
258
|
-
|
|
259
|
-
There are two methods:
|
|
260
|
-
|
|
261
|
-
| Method | Description |
|
|
262
|
-
| ------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
263
|
-
| `fromUnrealCallback` | Listens for callbacks matching a command or event key. Supports MetaBox commands and custom Unreal callback events. Returns `Observable<UnrealCallbackDescriptor[K]>`. |
|
|
264
|
-
| `observeCommandResponse` | Sends a command and waits for its matching response by `correlationId`. Returns `Observable<MetaBoxCommandList[K]>`. Includes timeout and error handling. |
|
|
265
|
-
|
|
266
|
-
**Custom Unreal callback events** (defined in `UnrealCallbackEventMap`):
|
|
267
|
-
|
|
268
|
-
| Event | Payload Type |
|
|
269
|
-
| -------------------------- | --------------------------------------------------- |
|
|
270
|
-
| `onSceneState` | `FSceneState` |
|
|
271
|
-
| `onFocusObject` | `FProductPayload` |
|
|
272
|
-
| `cameraChanged` | `FCameraChangedPayload` |
|
|
273
|
-
| `onObjectTransformChanged` | `{ objectName: string; transform: FTransformJson }` |
|
|
274
|
-
| `onChangeSequence` | `unknown` |
|
|
275
|
-
| `onFinishedSequence` | `unknown` |
|
|
276
|
-
|
|
277
|
-
```ts
|
|
278
|
-
import { Component, inject } from '@angular/core';
|
|
279
|
-
import { UnrealCallbackService } from '@3dsource/angular-unreal-module';
|
|
280
|
-
import { UnrealCommunicatorService } from '@3dsource/angular-unreal-module';
|
|
281
|
-
import { MetaBoxCommand } from '@3dsource/types-unreal';
|
|
282
|
-
|
|
283
|
-
@Component({ standalone: true, template: '' })
|
|
284
|
-
export class MyComponent {
|
|
285
|
-
private callbackService = inject(UnrealCallbackService);
|
|
286
|
-
private communicator = inject(UnrealCommunicatorService);
|
|
287
|
-
|
|
288
|
-
listenForCallbacks() {
|
|
289
|
-
// Listen for a MetaBox command callback
|
|
290
|
-
this.callbackService.fromUnrealCallback(MetaBoxCommand.FLoadProductCommand).subscribe((data) => console.log('Product loaded:', data));
|
|
291
|
-
|
|
292
|
-
// Listen for a custom Unreal event
|
|
293
|
-
this.callbackService.fromUnrealCallback('cameraChanged').subscribe((data) => console.log('Camera changed:', data));
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
sendAndObserve() {
|
|
297
|
-
// Send a command and observe its response (with correlationId matching)
|
|
298
|
-
this.callbackService
|
|
299
|
-
.observeCommandResponse(
|
|
300
|
-
{ command: MetaBoxCommand.FLoopBackCommand },
|
|
301
|
-
(data) => this.communicator.sendCommandToUnreal(data),
|
|
302
|
-
60000, // timeout in ms (default: 60000)
|
|
303
|
-
true, // emit on timeout (default: true)
|
|
304
|
-
)
|
|
305
|
-
.subscribe((response) => console.log('Response:', response));
|
|
306
|
-
}
|
|
307
|
-
}
|
|
308
|
-
```
|
|
309
|
-
|
|
310
|
-
## Exported API
|
|
311
|
-
|
|
312
|
-
### Components
|
|
313
|
-
|
|
314
|
-
| Component | Selector | Description |
|
|
315
|
-
| ------------------------------- | ------------------ | -------------------------------------- |
|
|
316
|
-
| `UnrealSceneComponent` | `app-unreal-scene` | Main scene container with video stream |
|
|
317
|
-
| `AfkTimeoutModalComponent` | — | AFK timeout warning modal |
|
|
318
|
-
| `FreezeFrameComponent` | — | Freeze frame overlay |
|
|
319
|
-
| `LowBandwidthModalComponent` | — | Low bandwidth warning modal |
|
|
320
|
-
| `LowBandwidthDetectorComponent` | — | Low bandwidth detector |
|
|
321
|
-
| `ImageLoadingSrcComponent` | — | Loading image overlay |
|
|
322
|
-
| `IntroSrcComponent` | — | Intro image/video overlay |
|
|
323
|
-
| `VideoStatsComponent` | — | Video statistics display |
|
|
324
|
-
| `StatGraphComponent` | — | Statistics graph |
|
|
325
|
-
| `WebrtcErrorModalComponent` | — | WebRTC error modal |
|
|
326
|
-
|
|
327
|
-
### Services
|
|
328
|
-
|
|
329
|
-
| Service | Description |
|
|
330
|
-
| ------------------------------ | --------------------------------------------------------------- |
|
|
331
|
-
| `UnrealCommunicatorService` | Send commands and UI interactions to Unreal |
|
|
332
|
-
| `UnrealCallbackService` | Listen for Unreal callback events and observe command responses |
|
|
333
|
-
| `AggregatorService` | Aggregates data channel messages from Unreal |
|
|
334
|
-
| `SignallingService` | Manages WebSocket signalling connection |
|
|
335
|
-
| `VideoService` | Manages video element and stats |
|
|
336
|
-
| `WebRtcPlayerService` | Manages WebRTC peer connection |
|
|
337
|
-
| `FreezeFrameService` | Handles freeze frame images |
|
|
338
|
-
| `AFKService` | AFK (away from keyboard) detection and timeout |
|
|
339
|
-
| `DevModeService` | Toggle dev mode for debugging |
|
|
340
|
-
| `FileReceiverService` | Receives files from Unreal via data channel |
|
|
341
|
-
| `FileHandlerService` | Processes received files |
|
|
342
|
-
| `RegionsPingService` | Pings regions to determine latency |
|
|
343
|
-
| `CommandTelemetryService` | Records command telemetry |
|
|
344
|
-
| `StreamStatusTelemetryService` | Reports stream status telemetry |
|
|
345
|
-
| `AnalyticsService` | Analytics event tracking |
|
|
346
|
-
| `FpsMonitorService` | FPS monitoring |
|
|
347
|
-
|
|
348
|
-
### Pipes
|
|
349
|
-
|
|
350
|
-
| Pipe | Description |
|
|
351
|
-
| ---------- | ------------------------------------------------------------ |
|
|
352
|
-
| `SafePipe` | Sanitizes a value for the requested Angular security context |
|
|
353
|
-
|
|
354
|
-
### Interfaces
|
|
355
|
-
|
|
356
|
-
| Interface | Description |
|
|
357
|
-
| -------------------------- | ---------------------------------------------------------------------------- |
|
|
358
|
-
| `UnrealInitialConfig` | Shape for `UNREAL_CONFIG` injection token |
|
|
359
|
-
| `StreamConfig` | Stream configuration (autoStart, warnTimeout) |
|
|
360
|
-
| `StreamResolutionProps` | Stream resolution width/height |
|
|
361
|
-
| `UnrealCallbackEventMap` | Custom Unreal callback events pushed from Unreal via data channel |
|
|
362
|
-
| `UnrealCallbackDescriptor` | Combined map of MetaBoxCommandList and UnrealCallbackEventMap callback types |
|
|
363
|
-
|
|
364
|
-
## Features
|
|
365
|
-
|
|
366
|
-
- Standalone Unreal Scene Component
|
|
367
|
-
- Command and UI Interaction API via `UnrealCommunicatorService`
|
|
368
|
-
- Callback listener and command response observer via `UnrealCallbackService`
|
|
369
|
-
- Event-driven status UI (freeze frame, video stats, play overlay, AFK, low bandwidth)
|
|
370
|
-
- NgRx-powered state management and effects
|
|
371
|
-
- **Required** initial configuration via `UNREAL_CONFIG` injection token
|
|
372
|
-
- Auto-reconnection on WebRTC/DataChannel failures (configurable)
|
|
373
|
-
- File receiving from Unreal Engine via data channel
|
|
374
|
-
- Analytics and FPS monitoring
|
|
375
|
-
- Playwright testing mode with mock service substitution
|
|
376
|
-
|
|
377
|
-
## Examples
|
|
378
|
-
|
|
379
|
-
Check the demo application for complete usage examples:
|
|
380
|
-
|
|
381
|
-
```shell
|
|
382
|
-
pnpm demo:start
|
|
383
|
-
```
|
|
384
|
-
|
|
385
|
-
See also: `projects/demo/src/app/demo-layout/info-pages/unreal-scene-demo/constants/unreal.routes.ts` for a real-world provider configuration example.
|
|
386
|
-
|
|
387
|
-
## Repository development
|
|
388
|
-
|
|
389
|
-
Run package commands from the repository root:
|
|
390
|
-
|
|
391
|
-
```shell
|
|
392
|
-
pnpm
|
|
393
|
-
pnpm
|
|
394
|
-
pnpm
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
```
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
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 `>=19.0.0 <23.0.0`
|
|
24
|
+
- NgRx store and effects `>=19.0.0 <23.0.0`
|
|
25
|
+
- Angular CDK `>=19.0.0 <23.0.0` — used for dialog overlays
|
|
26
|
+
- RxJS `>=7.8.0 <8.0.0`
|
|
27
|
+
- `provideHttpClient()` — required by internal services (telemetry, signalling, regions ping, error reporting)
|
|
28
|
+
|
|
29
|
+
### Peer Dependencies
|
|
30
|
+
|
|
31
|
+
This library requires the following peer dependencies:
|
|
32
|
+
|
|
33
|
+
```json
|
|
34
|
+
{
|
|
35
|
+
"@3dsource/source-ui-native": ">=1.0.9",
|
|
36
|
+
"@3dsource/types-unreal": ">=0.0.7",
|
|
37
|
+
"@3dsource/utils": ">=1.0.21",
|
|
38
|
+
"@angular/cdk": ">=19.0.0 <23.0.0",
|
|
39
|
+
"@angular/common": ">=19.0.0 <23.0.0",
|
|
40
|
+
"@angular/core": ">=19.0.0 <23.0.0",
|
|
41
|
+
"@angular/forms": ">=19.0.0 <23.0.0",
|
|
42
|
+
"@angular/platform-browser": ">=19.0.0 <23.0.0",
|
|
43
|
+
"@ngrx/effects": ">=19.0.0 <23.0.0",
|
|
44
|
+
"@ngrx/store": ">=19.0.0 <23.0.0",
|
|
45
|
+
"rxjs": ">=7.8.0 <8.0.0"
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### Library Installation
|
|
50
|
+
|
|
51
|
+
```shell
|
|
52
|
+
npm i @3dsource/angular-unreal-module
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Usage
|
|
56
|
+
|
|
57
|
+
The API is fully standalone (no NgModule). Use providers and components as shown below.
|
|
58
|
+
|
|
59
|
+
### 1) Provide the state and config at the application root
|
|
60
|
+
|
|
61
|
+
Add providers in your application bootstrap (e.g., `app.config.ts`):
|
|
62
|
+
|
|
63
|
+
> **⚠️ 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.
|
|
64
|
+
|
|
65
|
+
```ts
|
|
66
|
+
import { ApplicationConfig } from '@angular/core';
|
|
67
|
+
import { provideRouter } from '@angular/router';
|
|
68
|
+
import { provideHttpClient } from '@angular/common/http';
|
|
69
|
+
import { provideStore } from '@ngrx/store';
|
|
70
|
+
import { provideUnrealState, UNREAL_CONFIG } from '@3dsource/angular-unreal-module';
|
|
71
|
+
|
|
72
|
+
export const appConfig: ApplicationConfig = {
|
|
73
|
+
providers: [
|
|
74
|
+
provideRouter([]),
|
|
75
|
+
provideHttpClient(),
|
|
76
|
+
|
|
77
|
+
// Root NgRx (if not already added in your app)
|
|
78
|
+
provideStore(),
|
|
79
|
+
provideUnrealState(),
|
|
80
|
+
|
|
81
|
+
// Required: Unreal initial configuration
|
|
82
|
+
{
|
|
83
|
+
provide: UNREAL_CONFIG,
|
|
84
|
+
useValue: {
|
|
85
|
+
customErrorsEndpoint: '', // Endpoint for custom error reporting
|
|
86
|
+
commandTelemetryReceiver: '', // Endpoint for command telemetry
|
|
87
|
+
regionsPingUrl: '', // URL prefix for regions latency ping
|
|
88
|
+
screenLockerContainerId: '', // DOM container id for screen locker overlay
|
|
89
|
+
dataChannelConnectionTimeout: 8000, // Timeout in ms for data channel connection (default: 8000)
|
|
90
|
+
streamTelemetryV2Url: '', // Endpoint for stream-status telemetry
|
|
91
|
+
fpsMonitor: false, // Enable FPS monitoring
|
|
92
|
+
autoHighResolution: false, // Raise resolution after the scene becomes idle
|
|
93
|
+
playwright: false, // Mirrors the provider flag for services/effects
|
|
94
|
+
},
|
|
95
|
+
},
|
|
96
|
+
],
|
|
97
|
+
};
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
#### Minimal configuration
|
|
101
|
+
|
|
102
|
+
If you don't need custom endpoints, provide `UNREAL_CONFIG` with an empty object:
|
|
103
|
+
|
|
104
|
+
```ts
|
|
105
|
+
{ provide: UNREAL_CONFIG, useValue: {} },
|
|
106
|
+
provideUnrealState(),
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Every `UnrealInitialConfig` field is optional, but the `UNREAL_CONFIG` provider
|
|
110
|
+
itself is required. Available fields are `playwright`,
|
|
111
|
+
`customErrorsEndpoint`, `commandTelemetryReceiver`, `regionsPingUrl`,
|
|
112
|
+
`screenLockerContainerId`, `dataChannelConnectionTimeout`,
|
|
113
|
+
`streamTelemetryV2Url`, `fpsMonitor` and `autoHighResolution`.
|
|
114
|
+
|
|
115
|
+
### 2) Boot the engine in each lazy 3D route
|
|
116
|
+
|
|
117
|
+
`provideUnrealModule()` registers the effects and initializes the streaming
|
|
118
|
+
services. Put it on every lazy route that renders a 3D scene:
|
|
119
|
+
|
|
120
|
+
```ts
|
|
121
|
+
import { Routes } from '@angular/router';
|
|
122
|
+
import { provideUnrealModule } from '@3dsource/angular-unreal-module';
|
|
123
|
+
|
|
124
|
+
export const STREAM_ROUTES: Routes = [
|
|
125
|
+
{
|
|
126
|
+
path: ':id',
|
|
127
|
+
loadComponent: () => import('./stream.component').then((module) => module.StreamComponent),
|
|
128
|
+
providers: [provideUnrealModule()],
|
|
129
|
+
},
|
|
130
|
+
];
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
Keep `provideUnrealState()` and `UNREAL_CONFIG` at the root. Keeping
|
|
134
|
+
`provideUnrealModule()` in lazy routes also keeps the streaming engine out of
|
|
135
|
+
the initial application bundle.
|
|
136
|
+
|
|
137
|
+
### 3) Use the Unreal scene component
|
|
138
|
+
|
|
139
|
+
Import the component into a standalone component and use it in the template.
|
|
140
|
+
|
|
141
|
+
```ts
|
|
142
|
+
import { Component } from '@angular/core';
|
|
143
|
+
import { UnrealSceneComponent } from '@3dsource/angular-unreal-module';
|
|
144
|
+
|
|
145
|
+
@Component({
|
|
146
|
+
selector: 'app-root',
|
|
147
|
+
standalone: true,
|
|
148
|
+
imports: [UnrealSceneComponent],
|
|
149
|
+
template: ` <app-unreal-scene [isStudio]="false" [useContainerAsSizeProvider]="true" [resolutionSize]="{ width: 1920, height: 1080 }" (changeMouseOverScene)="onHover($event)" /> `,
|
|
150
|
+
})
|
|
151
|
+
export class AppComponent {
|
|
152
|
+
onHover(isOver: boolean) {
|
|
153
|
+
// handle mouse over scene
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
Component selector: `<app-unreal-scene>`
|
|
159
|
+
|
|
160
|
+
Inputs:
|
|
161
|
+
|
|
162
|
+
| Input | Type | Default |
|
|
163
|
+
| ---------------------------- | ----------------------------------- | ------------------------------- |
|
|
164
|
+
| `isStudio` | `boolean` | `false` |
|
|
165
|
+
| `useContainerAsSizeProvider` | `boolean` | `true` |
|
|
166
|
+
| `resolutionSize` | `{ width: number; height: number }` | `{ width: 1920, height: 1080 }` |
|
|
167
|
+
|
|
168
|
+
Outputs:
|
|
169
|
+
|
|
170
|
+
| Output | Type |
|
|
171
|
+
| ---------------------- | --------------------------- |
|
|
172
|
+
| `changeMouseOverScene` | `OutputEmitterRef<boolean>` |
|
|
173
|
+
|
|
174
|
+
### 4) Send commands / interactions to Unreal
|
|
175
|
+
|
|
176
|
+
Inject `UnrealCommunicatorService` to send commands or UI interactions. Types for command packets are provided by `@3dsource/types-unreal`.
|
|
177
|
+
|
|
178
|
+
There are three sending methods — choose based on your needs:
|
|
179
|
+
|
|
180
|
+
| Method | Description |
|
|
181
|
+
| --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
182
|
+
| `sendCommandToUnreal` | Full pipeline: adds `correlationId`, records telemetry, dispatches NgRx `commandStarted` action. **Recommended for application commands.** |
|
|
183
|
+
| `emitUIInteraction` | Sends the packet as a raw `UIInteraction` message. No telemetry or store dispatch. |
|
|
184
|
+
| `emitCommand` | Sends the packet as a raw `Command` message (for console commands, resolution changes, etc.). |
|
|
185
|
+
|
|
186
|
+
```ts
|
|
187
|
+
import { Component, inject } from '@angular/core';
|
|
188
|
+
import { UnrealCommunicatorService } from '@3dsource/angular-unreal-module';
|
|
189
|
+
import { MetaBoxCommand } from '@3dsource/types-unreal';
|
|
190
|
+
import type { MetaBoxCommandPacket } from '@3dsource/types-unreal';
|
|
191
|
+
|
|
192
|
+
@Component({ standalone: true, template: '' })
|
|
193
|
+
export class MyComponent {
|
|
194
|
+
private unreal = inject(UnrealCommunicatorService);
|
|
195
|
+
|
|
196
|
+
sendSomeCommand() {
|
|
197
|
+
// Recommended: use sendCommandToUnreal for full telemetry + store tracking
|
|
198
|
+
this.unreal.sendCommandToUnreal({
|
|
199
|
+
command: MetaBoxCommand.FChangeResolutionCommand,
|
|
200
|
+
payload: { resolution: { x: 1920, y: 1080 } },
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
sendRawUIInteraction() {
|
|
205
|
+
// Low-level: sends UIInteraction message without telemetry tracking
|
|
206
|
+
const packet = {
|
|
207
|
+
command: 'CustomCommand',
|
|
208
|
+
payload: { key: 'value' },
|
|
209
|
+
} as MetaBoxCommandPacket;
|
|
210
|
+
this.unreal.emitUIInteraction(packet);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
### 5) Store integration (actions & selectors)
|
|
216
|
+
|
|
217
|
+
`provideUnrealState()` registers the NgRx feature state `unrealFeature`. You
|
|
218
|
+
can dispatch actions and select state in your components:
|
|
219
|
+
|
|
220
|
+
```ts
|
|
221
|
+
import { inject } from '@angular/core';
|
|
222
|
+
import { Store } from '@ngrx/store';
|
|
223
|
+
import { disconnectStream, selectShowLoader, selectTotalProgress, setConfig, setOrchestrationContext, startStream, unrealFeature } from '@3dsource/angular-unreal-module';
|
|
224
|
+
|
|
225
|
+
// Dispatch actions
|
|
226
|
+
const store = inject(Store);
|
|
227
|
+
store.dispatch(startStream({ config: { autoStart: true, warnTimeout: 120 } }));
|
|
228
|
+
|
|
229
|
+
// Select state
|
|
230
|
+
const progress = store.selectSignal(selectTotalProgress);
|
|
231
|
+
const isVideoPlaying = store.selectSignal(unrealFeature.selectIsVideoPlaying);
|
|
232
|
+
const dataChannelConnected = store.selectSignal(unrealFeature.selectDataChannelConnected);
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
**Key selectors:**
|
|
236
|
+
|
|
237
|
+
- `selectTotalProgress` — Scene load progress (0–1 float)
|
|
238
|
+
- `selectShowLoader` — Whether loader screen should be visible
|
|
239
|
+
- `selectShowReconnectPopup` — Whether reconnect popup should be shown
|
|
240
|
+
- `selectIsVideoPlayingAndDataChannelConnected` — Combined readiness check
|
|
241
|
+
- `selectStreamConfig` — Current stream configuration
|
|
242
|
+
- `unrealFeature.selectCirrusConnected` — Signalling server connection status
|
|
243
|
+
- `unrealFeature.selectDataChannelConnected` — Data channel status
|
|
244
|
+
- `unrealFeature.selectViewportReady` — Viewport readiness
|
|
245
|
+
|
|
246
|
+
**Key actions:**
|
|
247
|
+
|
|
248
|
+
- `startStream` — Start streaming with config
|
|
249
|
+
- `setConfig` — Update stream configuration
|
|
250
|
+
- `setOrchestrationContext` — Set orchestration URLs and environment
|
|
251
|
+
- `disconnectStream` — Disconnect with reason
|
|
252
|
+
- `destroyUnrealScene` — Full teardown
|
|
253
|
+
- `reconnectPeer` — Trigger peer reconnection
|
|
254
|
+
|
|
255
|
+
### 6) Listen for Unreal callbacks
|
|
256
|
+
|
|
257
|
+
Inject `UnrealCallbackService` to listen for callback events from Unreal Engine and to observe command responses.
|
|
258
|
+
|
|
259
|
+
There are two methods:
|
|
260
|
+
|
|
261
|
+
| Method | Description |
|
|
262
|
+
| ------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
263
|
+
| `fromUnrealCallback` | Listens for callbacks matching a command or event key. Supports MetaBox commands and custom Unreal callback events. Returns `Observable<UnrealCallbackDescriptor[K]>`. |
|
|
264
|
+
| `observeCommandResponse` | Sends a command and waits for its matching response by `correlationId`. Returns `Observable<MetaBoxCommandList[K]>`. Includes timeout and error handling. |
|
|
265
|
+
|
|
266
|
+
**Custom Unreal callback events** (defined in `UnrealCallbackEventMap`):
|
|
267
|
+
|
|
268
|
+
| Event | Payload Type |
|
|
269
|
+
| -------------------------- | --------------------------------------------------- |
|
|
270
|
+
| `onSceneState` | `FSceneState` |
|
|
271
|
+
| `onFocusObject` | `FProductPayload` |
|
|
272
|
+
| `cameraChanged` | `FCameraChangedPayload` |
|
|
273
|
+
| `onObjectTransformChanged` | `{ objectName: string; transform: FTransformJson }` |
|
|
274
|
+
| `onChangeSequence` | `unknown` |
|
|
275
|
+
| `onFinishedSequence` | `unknown` |
|
|
276
|
+
|
|
277
|
+
```ts
|
|
278
|
+
import { Component, inject } from '@angular/core';
|
|
279
|
+
import { UnrealCallbackService } from '@3dsource/angular-unreal-module';
|
|
280
|
+
import { UnrealCommunicatorService } from '@3dsource/angular-unreal-module';
|
|
281
|
+
import { MetaBoxCommand } from '@3dsource/types-unreal';
|
|
282
|
+
|
|
283
|
+
@Component({ standalone: true, template: '' })
|
|
284
|
+
export class MyComponent {
|
|
285
|
+
private callbackService = inject(UnrealCallbackService);
|
|
286
|
+
private communicator = inject(UnrealCommunicatorService);
|
|
287
|
+
|
|
288
|
+
listenForCallbacks() {
|
|
289
|
+
// Listen for a MetaBox command callback
|
|
290
|
+
this.callbackService.fromUnrealCallback(MetaBoxCommand.FLoadProductCommand).subscribe((data) => console.log('Product loaded:', data));
|
|
291
|
+
|
|
292
|
+
// Listen for a custom Unreal event
|
|
293
|
+
this.callbackService.fromUnrealCallback('cameraChanged').subscribe((data) => console.log('Camera changed:', data));
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
sendAndObserve() {
|
|
297
|
+
// Send a command and observe its response (with correlationId matching)
|
|
298
|
+
this.callbackService
|
|
299
|
+
.observeCommandResponse(
|
|
300
|
+
{ command: MetaBoxCommand.FLoopBackCommand },
|
|
301
|
+
(data) => this.communicator.sendCommandToUnreal(data),
|
|
302
|
+
60000, // timeout in ms (default: 60000)
|
|
303
|
+
true, // emit on timeout (default: true)
|
|
304
|
+
)
|
|
305
|
+
.subscribe((response) => console.log('Response:', response));
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
## Exported API
|
|
311
|
+
|
|
312
|
+
### Components
|
|
313
|
+
|
|
314
|
+
| Component | Selector | Description |
|
|
315
|
+
| ------------------------------- | ------------------ | -------------------------------------- |
|
|
316
|
+
| `UnrealSceneComponent` | `app-unreal-scene` | Main scene container with video stream |
|
|
317
|
+
| `AfkTimeoutModalComponent` | — | AFK timeout warning modal |
|
|
318
|
+
| `FreezeFrameComponent` | — | Freeze frame overlay |
|
|
319
|
+
| `LowBandwidthModalComponent` | — | Low bandwidth warning modal |
|
|
320
|
+
| `LowBandwidthDetectorComponent` | — | Low bandwidth detector |
|
|
321
|
+
| `ImageLoadingSrcComponent` | — | Loading image overlay |
|
|
322
|
+
| `IntroSrcComponent` | — | Intro image/video overlay |
|
|
323
|
+
| `VideoStatsComponent` | — | Video statistics display |
|
|
324
|
+
| `StatGraphComponent` | — | Statistics graph |
|
|
325
|
+
| `WebrtcErrorModalComponent` | — | WebRTC error modal |
|
|
326
|
+
|
|
327
|
+
### Services
|
|
328
|
+
|
|
329
|
+
| Service | Description |
|
|
330
|
+
| ------------------------------ | --------------------------------------------------------------- |
|
|
331
|
+
| `UnrealCommunicatorService` | Send commands and UI interactions to Unreal |
|
|
332
|
+
| `UnrealCallbackService` | Listen for Unreal callback events and observe command responses |
|
|
333
|
+
| `AggregatorService` | Aggregates data channel messages from Unreal |
|
|
334
|
+
| `SignallingService` | Manages WebSocket signalling connection |
|
|
335
|
+
| `VideoService` | Manages video element and stats |
|
|
336
|
+
| `WebRtcPlayerService` | Manages WebRTC peer connection |
|
|
337
|
+
| `FreezeFrameService` | Handles freeze frame images |
|
|
338
|
+
| `AFKService` | AFK (away from keyboard) detection and timeout |
|
|
339
|
+
| `DevModeService` | Toggle dev mode for debugging |
|
|
340
|
+
| `FileReceiverService` | Receives files from Unreal via data channel |
|
|
341
|
+
| `FileHandlerService` | Processes received files |
|
|
342
|
+
| `RegionsPingService` | Pings regions to determine latency |
|
|
343
|
+
| `CommandTelemetryService` | Records command telemetry |
|
|
344
|
+
| `StreamStatusTelemetryService` | Reports stream status telemetry |
|
|
345
|
+
| `AnalyticsService` | Analytics event tracking |
|
|
346
|
+
| `FpsMonitorService` | FPS monitoring |
|
|
347
|
+
|
|
348
|
+
### Pipes
|
|
349
|
+
|
|
350
|
+
| Pipe | Description |
|
|
351
|
+
| ---------- | ------------------------------------------------------------ |
|
|
352
|
+
| `SafePipe` | Sanitizes a value for the requested Angular security context |
|
|
353
|
+
|
|
354
|
+
### Interfaces
|
|
355
|
+
|
|
356
|
+
| Interface | Description |
|
|
357
|
+
| -------------------------- | ---------------------------------------------------------------------------- |
|
|
358
|
+
| `UnrealInitialConfig` | Shape for `UNREAL_CONFIG` injection token |
|
|
359
|
+
| `StreamConfig` | Stream configuration (autoStart, warnTimeout) |
|
|
360
|
+
| `StreamResolutionProps` | Stream resolution width/height |
|
|
361
|
+
| `UnrealCallbackEventMap` | Custom Unreal callback events pushed from Unreal via data channel |
|
|
362
|
+
| `UnrealCallbackDescriptor` | Combined map of MetaBoxCommandList and UnrealCallbackEventMap callback types |
|
|
363
|
+
|
|
364
|
+
## Features
|
|
365
|
+
|
|
366
|
+
- Standalone Unreal Scene Component
|
|
367
|
+
- Command and UI Interaction API via `UnrealCommunicatorService`
|
|
368
|
+
- Callback listener and command response observer via `UnrealCallbackService`
|
|
369
|
+
- Event-driven status UI (freeze frame, video stats, play overlay, AFK, low bandwidth)
|
|
370
|
+
- NgRx-powered state management and effects
|
|
371
|
+
- **Required** initial configuration via `UNREAL_CONFIG` injection token
|
|
372
|
+
- Auto-reconnection on WebRTC/DataChannel failures (configurable)
|
|
373
|
+
- File receiving from Unreal Engine via data channel
|
|
374
|
+
- Analytics and FPS monitoring
|
|
375
|
+
- Playwright testing mode with mock service substitution
|
|
376
|
+
|
|
377
|
+
## Examples
|
|
378
|
+
|
|
379
|
+
Check the demo application for complete usage examples:
|
|
380
|
+
|
|
381
|
+
```shell
|
|
382
|
+
pnpm demo:start
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
See also: `projects/demo/src/app/demo-layout/info-pages/unreal-scene-demo/constants/unreal.routes.ts` for a real-world provider configuration example.
|
|
386
|
+
|
|
387
|
+
## Repository development
|
|
388
|
+
|
|
389
|
+
Run package commands from the repository root:
|
|
390
|
+
|
|
391
|
+
```shell
|
|
392
|
+
pnpm unreal:build
|
|
393
|
+
pnpm unreal:build:watch
|
|
394
|
+
pnpm unreal:lint
|
|
395
|
+
pnpm unreal:test
|
|
396
|
+
pnpm unreal:test:watch
|
|
397
|
+
pnpm unreal:test:signalling
|
|
398
|
+
pnpm unreal:test:signalling:leaks
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
`unreal:build` builds `source-ui-native`, `types-unreal` and `utils` before this
|
|
402
|
+
package. `unreal:build:watch` performs that initial build automatically and then
|
|
403
|
+
watches `angular-unreal-module`.
|
|
404
|
+
|
|
405
|
+
To version and publish:
|
|
406
|
+
|
|
407
|
+
```shell
|
|
408
|
+
pnpm unreal:release:patch
|
|
409
|
+
pnpm unreal:release:dev
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
The release command publishes to npm. After verifying the npm release, purge
|
|
413
|
+
the matching jsDelivr tag explicitly:
|
|
414
|
+
|
|
415
|
+
```shell
|
|
416
|
+
pnpm unreal:purge-cdn -- latest
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
## Engine requirements
|
|
420
|
+
|
|
421
|
+
- Node.js: >=24.16.0
|
|
422
|
+
- pnpm: 11.17.0 (activated from the root `packageManager` field via Corepack)
|