@3dsource/angular-unreal-module 0.0.44 → 0.0.46
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,16 +1,15 @@
|
|
|
1
1
|
# @3dsource/angular-unreal-module
|
|
2
2
|
|
|
3
|
-
A standalone Angular
|
|
4
|
-
communication between Angular applications and Unreal Engine, enabling interactive 3D experiences.
|
|
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.
|
|
5
4
|
|
|
6
5
|
## Overview
|
|
7
6
|
|
|
8
|
-
|
|
7
|
+
This package provides:
|
|
9
8
|
|
|
10
|
-
-
|
|
11
|
-
- Communication bridge
|
|
12
|
-
-
|
|
13
|
-
-
|
|
9
|
+
- Standalone Unreal scene component to embed UE stream
|
|
10
|
+
- Communication bridge (commands, UI interactions, input data)
|
|
11
|
+
- NgRx state and effects for 3D stream lifecycle
|
|
12
|
+
- Config and utilities for telemetry, errors, and regions ping
|
|
14
13
|
|
|
15
14
|
## Installation
|
|
16
15
|
|
|
@@ -21,82 +20,139 @@ The Angular Unreal Module provides:
|
|
|
21
20
|
|
|
22
21
|
### Peer Dependencies
|
|
23
22
|
|
|
24
|
-
This library requires the following peer dependencies:
|
|
23
|
+
This library requires the following peer dependencies (match or exceed versions):
|
|
25
24
|
|
|
26
25
|
```json
|
|
27
26
|
{
|
|
28
|
-
"@3dsource/source-ui-native": "
|
|
29
|
-
"@3dsource/types-unreal": "
|
|
30
|
-
"@3dsource/utils": "
|
|
31
|
-
"@angular/cdk": "
|
|
32
|
-
"@angular/common": "
|
|
33
|
-
"@angular/core": "
|
|
34
|
-
"@angular/forms": "
|
|
35
|
-
"@ngrx/effects": "
|
|
36
|
-
"@ngrx/
|
|
37
|
-
"@ngrx/store": "^19.1.0"
|
|
27
|
+
"@3dsource/source-ui-native": ">=1.0.9",
|
|
28
|
+
"@3dsource/types-unreal": ">=0.0.5",
|
|
29
|
+
"@3dsource/utils": ">=1.0.21",
|
|
30
|
+
"@angular/cdk": ">=19.0.0",
|
|
31
|
+
"@angular/common": ">=19.0.0",
|
|
32
|
+
"@angular/core": ">=19.0.0",
|
|
33
|
+
"@angular/forms": ">=19.0.0",
|
|
34
|
+
"@ngrx/effects": ">=19.0.0",
|
|
35
|
+
"@ngrx/store": ">=19.0.0"
|
|
38
36
|
}
|
|
39
37
|
```
|
|
40
38
|
|
|
41
39
|
### Library Installation
|
|
42
40
|
|
|
43
41
|
```shell
|
|
44
|
-
|
|
42
|
+
npm i @3dsource/angular-unreal-module
|
|
45
43
|
```
|
|
46
44
|
|
|
47
45
|
## Usage
|
|
48
46
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
1
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
@
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
47
|
+
The API is fully standalone (no NgModule). Use providers and components as shown below.
|
|
48
|
+
|
|
49
|
+
### 1) Provide the module services and store slice
|
|
50
|
+
|
|
51
|
+
Add providers in your application bootstrap (e.g., app.config.ts):
|
|
52
|
+
|
|
53
|
+
```ts
|
|
54
|
+
import { ApplicationConfig } from '@angular/core';
|
|
55
|
+
import { provideRouter } from '@angular/router';
|
|
56
|
+
import { provideStore } from '@ngrx/store';
|
|
57
|
+
import { provideEffects } from '@ngrx/effects';
|
|
58
|
+
import { provideAngularUnrealModule, UNREAL_CONFIG } from '@3dsource/angular-unreal-module';
|
|
59
|
+
|
|
60
|
+
export const appConfig: ApplicationConfig = {
|
|
61
|
+
providers: [
|
|
62
|
+
provideRouter([]),
|
|
63
|
+
// Root NgRx (if not already added in your app)
|
|
64
|
+
provideStore(),
|
|
65
|
+
provideEffects(),
|
|
66
|
+
|
|
67
|
+
// Unreal providers (adds feature state and effects internally)
|
|
68
|
+
...provideAngularUnrealModule(),
|
|
69
|
+
|
|
70
|
+
// Optional initial config
|
|
71
|
+
{ provide: UNREAL_CONFIG, useValue: {
|
|
72
|
+
// customErrorsEndpoint?: string,
|
|
73
|
+
// commandTelemetryReceiver?: string,
|
|
74
|
+
// regionsPingUrl?: string,
|
|
75
|
+
// screenLockerContainerId?: string,
|
|
76
|
+
// dataChannelConnectionTimeout?: number,
|
|
77
|
+
}
|
|
78
|
+
},
|
|
61
79
|
],
|
|
80
|
+
};
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### 2) Use the Unreal scene component
|
|
84
|
+
|
|
85
|
+
Import the component into a standalone component and use it in the template.
|
|
86
|
+
|
|
87
|
+
```ts
|
|
88
|
+
import { Component } from '@angular/core';
|
|
89
|
+
import { UnrealSceneComponent } from '@3dsource/angular-unreal-module';
|
|
90
|
+
|
|
91
|
+
@Component({
|
|
92
|
+
selector: 'app-root',
|
|
93
|
+
standalone: true,
|
|
94
|
+
imports: [UnrealSceneComponent],
|
|
95
|
+
template: `
|
|
96
|
+
<app-unreal-scene
|
|
97
|
+
[isStudio]="false"
|
|
98
|
+
[useContainerAsSizeProvider]="true"
|
|
99
|
+
[studioResolutionSize]="{ width: 1920, height: 1080 }"
|
|
100
|
+
(changeMouseOverScene)="onHover($event)"
|
|
101
|
+
></app-unreal-scene>
|
|
102
|
+
`,
|
|
62
103
|
})
|
|
63
|
-
export class
|
|
104
|
+
export class AppComponent {
|
|
105
|
+
onHover(isOver: boolean) {
|
|
106
|
+
// handle mouse over scene
|
|
107
|
+
}
|
|
108
|
+
}
|
|
64
109
|
```
|
|
65
110
|
|
|
66
|
-
|
|
111
|
+
Component selector: <app-unreal-scene>
|
|
67
112
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
113
|
+
Inputs:
|
|
114
|
+
- isStudio: boolean = false
|
|
115
|
+
- useContainerAsSizeProvider: boolean = true
|
|
116
|
+
- studioResolutionSize: { width: number; height: number } = { width: 1920, height: 1080 }
|
|
71
117
|
|
|
72
|
-
|
|
118
|
+
Outputs:
|
|
119
|
+
- changeMouseOverScene: EventEmitter<boolean>
|
|
73
120
|
|
|
74
|
-
|
|
121
|
+
### 3) Send commands / interactions to Unreal
|
|
75
122
|
|
|
76
|
-
|
|
77
|
-
import { UnrealService } from '@3dsource/angular-unreal-module';
|
|
123
|
+
Use UnrealCommunicatorService to send commands or UI interactions. Types for command packets are provided by @3dsource/types-unreal.
|
|
78
124
|
|
|
79
|
-
|
|
125
|
+
```ts
|
|
126
|
+
import { Component, inject } from '@angular/core';
|
|
127
|
+
import { UnrealCommunicatorService } from '@3dsource/angular-unreal-module';
|
|
128
|
+
import type { MetaBoxCommandPacket } from '@3dsource/types-unreal';
|
|
129
|
+
|
|
130
|
+
@Component({ standalone: true, template: '' })
|
|
80
131
|
export class MyComponent {
|
|
81
|
-
|
|
82
|
-
}
|
|
132
|
+
private unreal = inject(UnrealCommunicatorService);
|
|
83
133
|
|
|
84
|
-
|
|
85
|
-
|
|
134
|
+
sendSomeCommand() {
|
|
135
|
+
const packet: MetaBoxCommandPacket = {
|
|
86
136
|
command: 'SomeCommand',
|
|
87
|
-
parameters: { /* command parameters */ }
|
|
88
|
-
}
|
|
137
|
+
parameters: { /* command parameters */ },
|
|
138
|
+
} as MetaBoxCommandPacket;
|
|
139
|
+
|
|
140
|
+
// Records telemetry and dispatches store events
|
|
141
|
+
this.unreal.sendCommandToUnreal(packet);
|
|
142
|
+
// Or use:
|
|
143
|
+
// this.unreal.emitCommand(packet); // to send as Command message
|
|
144
|
+
// this.unreal.emitUIInteraction(packet); // to send as UIInteraction
|
|
89
145
|
}
|
|
90
146
|
}
|
|
91
147
|
```
|
|
92
148
|
|
|
93
149
|
## Features
|
|
94
150
|
|
|
95
|
-
-
|
|
96
|
-
-
|
|
97
|
-
-
|
|
98
|
-
-
|
|
99
|
-
-
|
|
151
|
+
- Standalone Unreal Scene Component
|
|
152
|
+
- Command and UI Interaction API via UnrealCommunicatorService
|
|
153
|
+
- Event-driven status UI (freeze frame, video stats, play overlay)
|
|
154
|
+
- NgRx-powered state management and effects
|
|
155
|
+
- Optional initial configuration via UNREAL_CONFIG token
|
|
100
156
|
|
|
101
157
|
## Examples
|
|
102
158
|
|
|
@@ -3099,7 +3099,7 @@ class UnrealEffects {
|
|
|
3099
3099
|
})));
|
|
3100
3100
|
});
|
|
3101
3101
|
this.forceLBMOff$ = createEffect(() => {
|
|
3102
|
-
return fromEvent(document, 'visibilitychange').pipe(map(() => document.visibilityState === 'visible'), filter(Truthy), withLatestFrom(this.store.select(unrealFeature.selectLowBandwidth)), filter(([, isLowBandwidth]) =>
|
|
3102
|
+
return fromEvent(document, 'visibilitychange').pipe(map(() => document.visibilityState === 'visible'), filter(Truthy), withLatestFrom(this.store.select(unrealFeature.selectLowBandwidth)), filter(([, isLowBandwidth]) => isLowBandwidth), tapLog('forceLBMOff$'), map(() => changeLowBandwidth({ lowBandwidth: false })));
|
|
3103
3103
|
});
|
|
3104
3104
|
this.resetFreezeFrameOnLowBandwidthTriggered$ = createEffect(() => {
|
|
3105
3105
|
return this.actions$.pipe(ofType(changeLowBandwidth), map(({ lowBandwidth }) => lowBandwidth), distinctUntilChanged(), map(() => setFreezeFrame({ dataUrl: null, progress: null })));
|
|
@@ -3240,7 +3240,7 @@ const selectIsVideoPlayingAndDataChannelConnected = createSelector(unrealFeature
|
|
|
3240
3240
|
const selectSignalingParameters = createSelector(unrealFeature.selectSsData, unrealFeature.selectAwsInstance, unrealFeature.selectSsInfo, (data, instance, ssInfo) => {
|
|
3241
3241
|
const info = [];
|
|
3242
3242
|
if (data) {
|
|
3243
|
-
info.push(`${data.cirrusVersion}, ${data.branchInfo}`);
|
|
3243
|
+
info.push(`${data.cirrusVersion}, ${data.branchInfo}, ${data.instanceType}`);
|
|
3244
3244
|
info.push(`Unreal App Version: ${data.streamerVersion}`);
|
|
3245
3245
|
info.push(`APP: ${data.streamPath}${data.streamApp}`);
|
|
3246
3246
|
}
|