Video
Plays a video file as a texture on a quad. Supports green-screen keying (isGreenScreen, backgroundColor, similarity, smoothness, spill). The video element, texture, and material are runtime-only and re-created when the project loads.
Managed by:
VideoSystem
Editor inspector

Properties
| Property | Type | Description |
|---|---|---|
path | string | Source URL or localasset:// path of the video file. |
options | typeof DEFAULT_VIDEO_OPTIONS | Playback + green-screen options. |
object | THREE.Object3D | null | Live three.js object hosting the video quad. null until built. |
videoElement | HTMLVideoElement | null | Underlying HTML video element. null until built. |
texture | THREE.VideoTexture | null | Three.js texture sampling the video element. null until built. |
material | THREE.Material | null | Material rendering the video texture (with green-screen shader when enabled). null until built. |
audioNode | THREE.Audio<GainNode> | THREE.PositionalAudio | null | THREE.js audio node connected to this video's audio stream via setMediaElementSource. Present only in preview when the camera listener is available. null in editor mode. |
isPlaying | boolean | Whether the video should be playing. Managed by VideoSystem in preview. Non-enumerable — not persisted to snapshots or save data. Set via play / stop. |
isPaused | boolean | Whether the video is paused mid-playback (position is preserved). Non-enumerable — not persisted to snapshots or save data. Set via pause / play / stop. |
API reference
- Class:
VideoComponent - Source:
core/components/Video.ts
Scripting examples
Component access patterns
Use this.getComponent(X) to access a component on the entity this script is attached to. Use this.world.getEntityByName to find another entity by name, then this.world.getComponent to read its component:
// Component on the entity this script is on
const video = this.getComponent(VideoComponent);
// Component on another entity, found by its scene name
const other = this.world.getEntityByName("Screen");
if (other) {
const video = this.world.getComponent(other.entityId, VideoComponent);
}Play / pause on key press
Toggle video playback when the player presses Space.
import { Behaviour, VideoComponent, KeyboardKeys } from "@relu-interactives/spatial-ecs";
export default class VideoController extends Behaviour {
protected onUpdate() {
const video = this.getComponent(VideoComponent);
if (!video) return;
if (this.world.getKeyDown(KeyboardKeys.Space)) {
if (video.isPlaying) {
video.pause();
} else {
video.play();
}
}
}
}Inspector-driven volume and loop
Expose volume and loop settings as inspector fields so they can be tuned without re-entering the code.
import { Behaviour, VideoComponent } from "@relu-interactives/spatial-ecs";
import type { FloatInput, BooleanInput } from "@relu-interactives/spatial-ecs";
export default class VideoSettings extends Behaviour {
data = {
volume: 1 as FloatInput,
loop: true as BooleanInput,
};
protected onUpdate() {
const video = this.getComponent(VideoComponent);
if (!video) return;
video.options.volume = this.data.volume;
video.options.loop = this.data.loop;
}
}Via ComponentInput in the inspector
You can also pick this component from the inspector using a ComponentInput field. Assign any entity in the inspector and the field resolves to the live VideoComponent instance at runtime.
import {
Behaviour,
VideoComponent,
type ComponentInput,
} from "@relu-interactives/spatial-ecs";
export default class Example extends Behaviour {
data = {
targetVideo: {
type: "component",
value: null,
} as unknown as ComponentInput,
};
protected onUpdate() {
const video = this.data.targetVideo.value as VideoComponent | null;
if (!video) return;
// Use the live component instance.
}
}Via EntityInput in the inspector
Alternatively, pick an entity from the inspector using an EntityInput field and then read the component off that entity via world.getComponent:
import {
Behaviour,
VideoComponent,
type EntityInput,
type WorldEntityView,
} from "@relu-interactives/spatial-ecs";
export default class Example extends Behaviour {
data = {
targetEntity: { type: "entity", value: null } as unknown as EntityInput,
};
protected onUpdate() {
const entity = this.data.targetEntity.value as WorldEntityView | null;
if (!entity) return;
const video = this.world.getComponent(
entity.entityId,
VideoComponent,
) as VideoComponent | null;
if (!video) return;
// Use the component on the picked entity.
}
}Playback methods
Use video.play(), video.pause(), and video.stop() to control playback. These update isPlaying / isPaused so the VideoSystem applies the correct HTML video element call in preview.

