
Research
Supply Chain Attack on Axios Pulls Malicious Dependency from npm
A supply chain attack on Axios introduced a malicious dependency, plain-crypto-js@4.2.1, published minutes earlier and absent from the project’s GitHub releases.
@3dsource/angular-unreal-module
Advanced tools
Angular Unreal module for connect with unreal engine stream
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.
This package provides:
provideHttpClient() — required by internal services (telemetry, signalling, regions ping, error reporting)This library requires the following peer dependencies (match or exceed versions):
{
"@3dsource/source-ui-native": ">=1.0.9",
"@3dsource/types-unreal": ">=0.0.7",
"@3dsource/utils": ">=1.0.21",
"@angular/cdk": ">=18.0.0",
"@angular/common": ">=18.0.0",
"@angular/core": ">=18.0.0",
"@angular/forms": ">=18.0.0",
"@ngrx/effects": ">=18.0.0",
"@ngrx/store": ">=18.0.0"
}
npm i @3dsource/angular-unreal-module
The API is fully standalone (no NgModule). Use providers and components as shown below.
Add providers in your application bootstrap (e.g., app.config.ts):
⚠️ Important:
UNREAL_CONFIGis required — multiple internal services inject it without{ optional: true }. Omitting it will cause aNullInjectorErrorat runtime. You can provide it with an empty object{}as a minimum.
import { ApplicationConfig } from '@angular/core';
import { provideRouter } from '@angular/router';
import { provideHttpClient } from '@angular/common/http';
import { provideStore } from '@ngrx/store';
import { provideEffects } from '@ngrx/effects';
import { provideAngularUnrealModule, UNREAL_CONFIG } from '@3dsource/angular-unreal-module';
export const appConfig: ApplicationConfig = {
providers: [
provideRouter([]),
provideHttpClient(),
// Root NgRx (if not already added in your app)
provideStore(),
provideEffects(),
// Required: Unreal initial configuration
{
provide: UNREAL_CONFIG,
useValue: {
customErrorsEndpoint: '', // Endpoint for custom error reporting
commandTelemetryReceiver: '', // Endpoint for command telemetry
regionsPingUrl: '', // URL prefix for regions latency ping
screenLockerContainerId: '', // DOM container id for screen locker overlay
dataChannelConnectionTimeout: 8000, // Timeout in ms for data channel connection (default: 8000)
playwright: false, // Mirrors the provider flag for services/effects
reconnect: {
// Auto-reconnection configuration
enabled: true, // Enable auto-reconnection (default: true)
maxAttempts: 3, // Max reconnection attempts (default: 3)
delayMs: 1000, // Delay between attempts in ms (default: 1000)
onIceFailure: true, // Reconnect on ICE connection failure (default: true)
onDataChannelClose: true, // Reconnect on DataChannel close (default: true)
},
},
},
// Unreal providers (adds feature state and effects internally)
// Tip: pass { playwright: true } to switch to testing/dummy services
provideAngularUnrealModule({ playwright: false }),
],
};
If you don't need custom endpoints, provide UNREAL_CONFIG with an empty object:
{ provide: UNREAL_CONFIG, useValue: {} },
provideAngularUnrealModule(),
Import the component into a standalone component and use it in the template.
import { Component } from '@angular/core';
import { UnrealSceneComponent } from '@3dsource/angular-unreal-module';
@Component({
selector: 'app-root',
standalone: true,
imports: [UnrealSceneComponent],
template: ` <app-unreal-scene [isStudio]="false" [useContainerAsSizeProvider]="true" [studioResolutionSize]="{ width: 1920, height: 1080 }" (changeMouseOverScene)="onHover($event)"> </app-unreal-scene> `,
})
export class AppComponent {
onHover(isOver: boolean) {
// handle mouse over scene
}
}
Component selector: <app-unreal-scene>
Inputs:
| Input | Type | Default |
|---|---|---|
isStudio | boolean | false |
useContainerAsSizeProvider | boolean | true |
studioResolutionSize | { width: number; height: number } | { width: 1920, height: 1080 } |
Outputs:
| Output | Type |
|---|---|
changeMouseOverScene | OutputEmitterRef<boolean> |
Inject UnrealCommunicatorService to send commands or UI interactions. Types for command packets are provided by @3dsource/types-unreal.
There are three sending methods — choose based on your needs:
| Method | Description |
|---|---|
sendCommandToUnreal | Full pipeline: adds correlationId, records telemetry, dispatches NgRx commandStarted action. Recommended for application commands. |
emitUIInteraction | Sends the packet as a raw UIInteraction message. No telemetry or store dispatch. |
emitCommand | Sends the packet as a raw Command message (for console commands, resolution changes, etc.). |
import { Component, inject } from '@angular/core';
import { UnrealCommunicatorService } from '@3dsource/angular-unreal-module';
import { MetaBoxCommand } from '@3dsource/types-unreal';
import type { MetaBoxCommandPacket } from '@3dsource/types-unreal';
@Component({ standalone: true, template: '' })
export class MyComponent {
private unreal = inject(UnrealCommunicatorService);
sendSomeCommand() {
// Recommended: use sendCommandToUnreal for full telemetry + store tracking
this.unreal.sendCommandToUnreal({
command: MetaBoxCommand.FChangeResolutionCommand,
payload: { resolution: { x: 1920, y: 1080 } },
});
}
sendRawUIInteraction() {
// Low-level: sends UIInteraction message without telemetry tracking
const packet = {
command: 'CustomCommand',
payload: { key: 'value' },
} as MetaBoxCommandPacket;
this.unreal.emitUIInteraction(packet);
}
}
The module registers an NgRx feature state commandsFeature. You can dispatch actions and select state in your components:
import { inject } from '@angular/core';
import { Store } from '@ngrx/store';
import { startStream, setConfig, setOrchestrationContext, disconnectStream, selectTotalProgress, selectShowLoader, commandsFeature } from '@3dsource/angular-unreal-module';
// Dispatch actions
const store = inject(Store);
store.dispatch(startStream({ config: { autoStart: true, warnTimeout: 120 } }));
// Select state
const progress = store.selectSignal(selectTotalProgress);
const isVideoPlaying = store.selectSignal(commandsFeature.selectIsVideoPlaying);
const dataChannelConnected = store.selectSignal(commandsFeature.selectDataChannelConnected);
Key selectors:
selectTotalProgress — Scene load progress (0–1 float)selectShowLoader — Whether loader screen should be visibleselectShowReconnectPopup — Whether reconnect popup should be shownselectIsVideoPlayingAndDataChannelConnected — Combined readiness checkselectStreamConfig — Current stream configurationcommandsFeature.selectCirrusConnected — Signalling server connection statuscommandsFeature.selectDataChannelConnected — Data channel statuscommandsFeature.selectViewportReady — Viewport readinessKey actions:
startStream — Start streaming with configsetConfig — Update stream configurationsetOrchestrationContext — Set orchestration URLs and environmentdisconnectStream — Disconnect with reasondestroyUnrealScene — Full teardownreconnectPeer — Trigger peer reconnectionInject UnrealCallbackService to listen for callback events from Unreal Engine and to observe command responses.
There are two methods:
| Method | Description |
|---|---|
fromUnrealCallback | Listens for callbacks matching a command or event key. Supports MetaBox commands and custom Unreal callback events. Returns Observable<UnrealCallbackDescriptor[K]>. |
observeCommandResponse | Sends a command and waits for its matching response by correlationId. Returns Observable<MetaBoxCommandList[K]>. Includes timeout and error handling. |
Custom Unreal callback events (defined in UnrealCallbackEventMap):
| Event | Payload Type |
|---|---|
onSceneState | FSceneState |
onFocusObject | FProductPayload |
cameraChanged | FCameraChangedPayload |
onObjectTransformChanged | { objectName: string; transform: FTransformJson } |
onChangeSequence | unknown |
onFinishedSequence | unknown |
import { Component, inject } from '@angular/core';
import { UnrealCallbackService } from '@3dsource/angular-unreal-module';
import { UnrealCommunicatorService } from '@3dsource/angular-unreal-module';
import { MetaBoxCommand } from '@3dsource/types-unreal';
@Component({ standalone: true, template: '' })
export class MyComponent {
private callbackService = inject(UnrealCallbackService);
private communicator = inject(UnrealCommunicatorService);
listenForCallbacks() {
// Listen for a MetaBox command callback
this.callbackService.fromUnrealCallback(MetaBoxCommand.FLoadProductCommand).subscribe((data) => console.log('Product loaded:', data));
// Listen for a custom Unreal event
this.callbackService.fromUnrealCallback('cameraChanged').subscribe((data) => console.log('Camera changed:', data));
}
sendAndObserve() {
// Send a command and observe its response (with correlationId matching)
this.callbackService
.observeCommandResponse(
{ command: MetaBoxCommand.FLoopBackCommand },
(data) => this.communicator.sendCommandToUnreal(data),
60000, // timeout in ms (default: 60000)
true, // emit on timeout (default: true)
)
.subscribe((response) => console.log('Response:', response));
}
}
| Component | Selector | Description |
|---|---|---|
UnrealSceneComponent | app-unreal-scene | Main scene container with video stream |
AfkTimeoutModalComponent | — | AFK timeout warning modal |
FreezeFrameComponent | — | Freeze frame overlay |
LowBandwidthModalComponent | — | Low bandwidth warning modal |
LowBandwidthIndicatorComponent | — | Low bandwidth indicator |
ImageLoadingSrcComponent | — | Loading image overlay |
IntroSrcComponent | — | Intro image/video overlay |
VideoStatsComponent | — | Video statistics display |
StatGraphComponent | — | Statistics graph |
WebrtcErrorModalComponent | — | WebRTC error modal |
| Service | Description |
|---|---|
UnrealCommunicatorService | Send commands and UI interactions to Unreal |
UnrealCallbackService | Listen for Unreal callback events and observe command responses |
AggregatorService | Aggregates data channel messages from Unreal |
SignallingService | Manages WebSocket signalling connection |
VideoService | Manages video element and stats |
WebRtcPlayerService | Manages WebRTC peer connection |
FreezeFrameService | Handles freeze frame images |
AFKService | AFK (away from keyboard) detection and timeout |
DevModeService | Toggle dev mode for debugging |
FileReceiverService | Receives files from Unreal via data channel |
FileHandlerService | Processes received files |
RegionsPingService | Pings regions to determine latency |
CommandTelemetryService | Records command telemetry |
StreamStatusTelemetryService | Reports stream status telemetry |
AnalyticsService | Analytics event tracking |
FpsMonitorService | FPS monitoring |
| Pipe | Description |
|---|---|
SafeHtmlPipe | Bypasses Angular HTML sanitizer |
| Interface | Description |
|---|---|
UnrealInitialConfig | Shape for UNREAL_CONFIG injection token |
ReconnectConfig | Auto-reconnection behavior configuration |
StreamConfig | Stream configuration (autoStart, warnTimeout) |
StreamResolutionProps | Stream resolution width/height |
UnrealCallbackEventMap | Custom Unreal callback events pushed from Unreal via data channel |
UnrealCallbackDescriptor | Combined map of MetaBoxCommandList and UnrealCallbackEventMap callback types |
UnrealCommunicatorServiceUnrealCallbackServiceUNREAL_CONFIG injection tokenCheck the demo application for complete usage examples:
npm run demo:start
See also: projects/demo/src/app/demo-layout/info-pages/unreal-scene-demo/constants/unreal.routes.ts for a real-world provider configuration example.
FAQs
Angular Unreal module for connect with unreal engine stream
We found that @3dsource/angular-unreal-module demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 4 open source maintainers collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Research
A supply chain attack on Axios introduced a malicious dependency, plain-crypto-js@4.2.1, published minutes earlier and absent from the project’s GitHub releases.

Research
Malicious versions of the Telnyx Python SDK on PyPI delivered credential-stealing malware via a multi-stage supply chain attack.

Security News
TeamPCP is partnering with ransomware group Vect to turn open source supply chain attacks on tools like Trivy and LiteLLM into large-scale ransomware operations.