@scenography/plugin-video 0.2.0
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/dist/data-BJdJij0e.cjs +34 -0
- package/dist/data-BJdJij0e.cjs.map +1 -0
- package/dist/data-DqD4TXso.mjs +23 -0
- package/dist/data-DqD4TXso.mjs.map +1 -0
- package/dist/data.cjs +4 -0
- package/dist/data.d.cts +2 -0
- package/dist/data.d.mts +2 -0
- package/dist/data.mjs +2 -0
- package/dist/index-CtaN02zR.d.cts +45 -0
- package/dist/index-CtaN02zR.d.mts +45 -0
- package/dist/index.cjs +79 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +40 -0
- package/dist/index.d.mts +40 -0
- package/dist/index.mjs +74 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +52 -0
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
let _scenography_scene = require("@scenography/scene");
|
|
2
|
+
//#region src/data/validate.ts
|
|
3
|
+
const validateVideo = (video) => (0, _scenography_scene.validate)([
|
|
4
|
+
(0, _scenography_scene.existsProp)("id", "Video is missing an id."),
|
|
5
|
+
(0, _scenography_scene.existsProp)("src", "Video is missing a src."),
|
|
6
|
+
(0, _scenography_scene.existsProp)("position"),
|
|
7
|
+
(0, _scenography_scene.propIs)("position", _scenography_scene.isVec3, "position must be [x, y, z]."),
|
|
8
|
+
(0, _scenography_scene.existsProp)("size"),
|
|
9
|
+
(0, _scenography_scene.propIs)("size", _scenography_scene.isVec2, "size must be [width, height]."),
|
|
10
|
+
(0, _scenography_scene.propIs)("rotation", _scenography_scene.isFiniteNumber, "rotation must be a finite number.")
|
|
11
|
+
])(video);
|
|
12
|
+
//#endregion
|
|
13
|
+
//#region src/data/plugin.ts
|
|
14
|
+
/** The data half of the video plugin: owns the `videos` scene key (a collection). */
|
|
15
|
+
const videoData = {
|
|
16
|
+
kind: "videos",
|
|
17
|
+
cardinality: "many",
|
|
18
|
+
validate: (video) => validateVideo(video)
|
|
19
|
+
};
|
|
20
|
+
//#endregion
|
|
21
|
+
Object.defineProperty(exports, "validateVideo", {
|
|
22
|
+
enumerable: true,
|
|
23
|
+
get: function() {
|
|
24
|
+
return validateVideo;
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
Object.defineProperty(exports, "videoData", {
|
|
28
|
+
enumerable: true,
|
|
29
|
+
get: function() {
|
|
30
|
+
return videoData;
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
//# sourceMappingURL=data-BJdJij0e.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"data-BJdJij0e.cjs","names":["isVec3","isVec2","isFiniteNumber"],"sources":["../src/data/validate.ts","../src/data/plugin.ts"],"sourcesContent":["import {\n existsProp,\n isFiniteNumber,\n isVec2,\n isVec3,\n propIs,\n validate,\n type ValidationResult,\n} from \"@scenography/scene\";\n\nimport type { Video } from \"./video\";\n\nexport const validateVideo = (video: Video): ValidationResult =>\n validate<Video>([\n existsProp(\"id\", \"Video is missing an id.\"),\n existsProp(\"src\", \"Video is missing a src.\"),\n existsProp(\"position\"),\n propIs(\"position\", isVec3, \"position must be [x, y, z].\"),\n existsProp(\"size\"),\n propIs(\"size\", isVec2, \"size must be [width, height].\"),\n propIs(\"rotation\", isFiniteNumber, \"rotation must be a finite number.\"),\n ])(video);\n","import type { DataPlugin } from \"@scenography/scene\";\n\nimport { validateVideo } from \"./validate\";\nimport type { Video } from \"./video\";\n\n/** The data half of the video plugin: owns the `videos` scene key (a collection). */\nexport const videoData: DataPlugin<Video> = {\n kind: \"videos\",\n cardinality: \"many\",\n validate: (video) => validateVideo(video),\n};\n"],"mappings":";;AAYA,MAAa,iBAAiB,WAAA,GAAA,mBAAA,SAAA,CACZ;oCACH,MAAM,yBAAyB;oCAC/B,OAAO,yBAAyB;oCAChC,UAAU;gCACd,YAAYA,mBAAAA,QAAQ,6BAA6B;oCAC7C,MAAM;gCACV,QAAQC,mBAAAA,QAAQ,+BAA+B;gCAC/C,YAAYC,mBAAAA,gBAAgB,mCAAmC;AACxE,CAAC,CAAC,CAAC,KAAK;;;;ACfV,MAAa,YAA+B;CAC1C,MAAM;CACN,aAAa;CACb,WAAW,UAAU,cAAc,KAAK;AAC1C"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { existsProp, isFiniteNumber, isVec2, isVec3, propIs, validate } from "@scenography/scene";
|
|
2
|
+
//#region src/data/validate.ts
|
|
3
|
+
const validateVideo = (video) => validate([
|
|
4
|
+
existsProp("id", "Video is missing an id."),
|
|
5
|
+
existsProp("src", "Video is missing a src."),
|
|
6
|
+
existsProp("position"),
|
|
7
|
+
propIs("position", isVec3, "position must be [x, y, z]."),
|
|
8
|
+
existsProp("size"),
|
|
9
|
+
propIs("size", isVec2, "size must be [width, height]."),
|
|
10
|
+
propIs("rotation", isFiniteNumber, "rotation must be a finite number.")
|
|
11
|
+
])(video);
|
|
12
|
+
//#endregion
|
|
13
|
+
//#region src/data/plugin.ts
|
|
14
|
+
/** The data half of the video plugin: owns the `videos` scene key (a collection). */
|
|
15
|
+
const videoData = {
|
|
16
|
+
kind: "videos",
|
|
17
|
+
cardinality: "many",
|
|
18
|
+
validate: (video) => validateVideo(video)
|
|
19
|
+
};
|
|
20
|
+
//#endregion
|
|
21
|
+
export { validateVideo as n, videoData as t };
|
|
22
|
+
|
|
23
|
+
//# sourceMappingURL=data-DqD4TXso.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"data-DqD4TXso.mjs","names":[],"sources":["../src/data/validate.ts","../src/data/plugin.ts"],"sourcesContent":["import {\n existsProp,\n isFiniteNumber,\n isVec2,\n isVec3,\n propIs,\n validate,\n type ValidationResult,\n} from \"@scenography/scene\";\n\nimport type { Video } from \"./video\";\n\nexport const validateVideo = (video: Video): ValidationResult =>\n validate<Video>([\n existsProp(\"id\", \"Video is missing an id.\"),\n existsProp(\"src\", \"Video is missing a src.\"),\n existsProp(\"position\"),\n propIs(\"position\", isVec3, \"position must be [x, y, z].\"),\n existsProp(\"size\"),\n propIs(\"size\", isVec2, \"size must be [width, height].\"),\n propIs(\"rotation\", isFiniteNumber, \"rotation must be a finite number.\"),\n ])(video);\n","import type { DataPlugin } from \"@scenography/scene\";\n\nimport { validateVideo } from \"./validate\";\nimport type { Video } from \"./video\";\n\n/** The data half of the video plugin: owns the `videos` scene key (a collection). */\nexport const videoData: DataPlugin<Video> = {\n kind: \"videos\",\n cardinality: \"many\",\n validate: (video) => validateVideo(video),\n};\n"],"mappings":";;AAYA,MAAa,iBAAiB,UAC5B,SAAgB;CACd,WAAW,MAAM,yBAAyB;CAC1C,WAAW,OAAO,yBAAyB;CAC3C,WAAW,UAAU;CACrB,OAAO,YAAY,QAAQ,6BAA6B;CACxD,WAAW,MAAM;CACjB,OAAO,QAAQ,QAAQ,+BAA+B;CACtD,OAAO,YAAY,gBAAgB,mCAAmC;AACxE,CAAC,CAAC,CAAC,KAAK;;;;ACfV,MAAa,YAA+B;CAC1C,MAAM;CACN,aAAa;CACb,WAAW,UAAU,cAAc,KAAK;AAC1C"}
|
package/dist/data.cjs
ADDED
package/dist/data.d.cts
ADDED
package/dist/data.d.mts
ADDED
package/dist/data.mjs
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { DataPlugin, ValidationResult, Vec2, Vec3 } from "@scenography/scene";
|
|
2
|
+
|
|
3
|
+
//#region src/data/video.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* A flat video screen placed in the space, textured with an HTML video element
|
|
6
|
+
* (`.mp4`/`.webm`). Pure data: where the screen is and which file it plays.
|
|
7
|
+
* Playback (play/pause) and visibility are driven by `id` from the runtime
|
|
8
|
+
* through `ctx.video` — the definition stays serializable. (YouTube can't be used
|
|
9
|
+
* here: it has no streamable source for a WebGL texture.)
|
|
10
|
+
*/
|
|
11
|
+
interface Video {
|
|
12
|
+
id: string;
|
|
13
|
+
/** Video URL (`.mp4`/`.webm`). */
|
|
14
|
+
src: string;
|
|
15
|
+
/** World position `[x, y, z]` of the screen center. */
|
|
16
|
+
position: Vec3;
|
|
17
|
+
/** `[width, height]` of the screen in world units. */
|
|
18
|
+
size: Vec2;
|
|
19
|
+
/** Y-axis rotation in radians (the screen faces `+Z` before rotation). Defaults to `0`. */
|
|
20
|
+
rotation?: number;
|
|
21
|
+
/** Loop playback. Defaults to `true`. */
|
|
22
|
+
loop?: boolean;
|
|
23
|
+
/** Mute audio (required for autoplay without a user gesture). Defaults to `true`. */
|
|
24
|
+
muted?: boolean;
|
|
25
|
+
/** Start playing immediately. Defaults to `false` (behavior code plays it). */
|
|
26
|
+
autoplay?: boolean;
|
|
27
|
+
/** Start visible. Defaults to `true`. */
|
|
28
|
+
visible?: boolean;
|
|
29
|
+
}
|
|
30
|
+
declare module "@scenography/scene" {
|
|
31
|
+
interface Scene {
|
|
32
|
+
/** Video screens placed in the space — provided by `@scenography/plugin-video`. */
|
|
33
|
+
videos?: Video[];
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
//#endregion
|
|
37
|
+
//#region src/data/validate.d.ts
|
|
38
|
+
declare const validateVideo: (video: Video) => ValidationResult;
|
|
39
|
+
//#endregion
|
|
40
|
+
//#region src/data/plugin.d.ts
|
|
41
|
+
/** The data half of the video plugin: owns the `videos` scene key (a collection). */
|
|
42
|
+
declare const videoData: DataPlugin<Video>;
|
|
43
|
+
//#endregion
|
|
44
|
+
export { validateVideo as n, Video as r, videoData as t };
|
|
45
|
+
//# sourceMappingURL=index-CtaN02zR.d.cts.map
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { DataPlugin, ValidationResult, Vec2, Vec3 } from "@scenography/scene";
|
|
2
|
+
|
|
3
|
+
//#region src/data/video.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* A flat video screen placed in the space, textured with an HTML video element
|
|
6
|
+
* (`.mp4`/`.webm`). Pure data: where the screen is and which file it plays.
|
|
7
|
+
* Playback (play/pause) and visibility are driven by `id` from the runtime
|
|
8
|
+
* through `ctx.video` — the definition stays serializable. (YouTube can't be used
|
|
9
|
+
* here: it has no streamable source for a WebGL texture.)
|
|
10
|
+
*/
|
|
11
|
+
interface Video {
|
|
12
|
+
id: string;
|
|
13
|
+
/** Video URL (`.mp4`/`.webm`). */
|
|
14
|
+
src: string;
|
|
15
|
+
/** World position `[x, y, z]` of the screen center. */
|
|
16
|
+
position: Vec3;
|
|
17
|
+
/** `[width, height]` of the screen in world units. */
|
|
18
|
+
size: Vec2;
|
|
19
|
+
/** Y-axis rotation in radians (the screen faces `+Z` before rotation). Defaults to `0`. */
|
|
20
|
+
rotation?: number;
|
|
21
|
+
/** Loop playback. Defaults to `true`. */
|
|
22
|
+
loop?: boolean;
|
|
23
|
+
/** Mute audio (required for autoplay without a user gesture). Defaults to `true`. */
|
|
24
|
+
muted?: boolean;
|
|
25
|
+
/** Start playing immediately. Defaults to `false` (behavior code plays it). */
|
|
26
|
+
autoplay?: boolean;
|
|
27
|
+
/** Start visible. Defaults to `true`. */
|
|
28
|
+
visible?: boolean;
|
|
29
|
+
}
|
|
30
|
+
declare module "@scenography/scene" {
|
|
31
|
+
interface Scene {
|
|
32
|
+
/** Video screens placed in the space — provided by `@scenography/plugin-video`. */
|
|
33
|
+
videos?: Video[];
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
//#endregion
|
|
37
|
+
//#region src/data/validate.d.ts
|
|
38
|
+
declare const validateVideo: (video: Video) => ValidationResult;
|
|
39
|
+
//#endregion
|
|
40
|
+
//#region src/data/plugin.d.ts
|
|
41
|
+
/** The data half of the video plugin: owns the `videos` scene key (a collection). */
|
|
42
|
+
declare const videoData: DataPlugin<Video>;
|
|
43
|
+
//#endregion
|
|
44
|
+
export { validateVideo as n, Video as r, videoData as t };
|
|
45
|
+
//# sourceMappingURL=index-CtaN02zR.d.mts.map
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
const require_data = require("./data-BJdJij0e.cjs");
|
|
3
|
+
let three = require("three");
|
|
4
|
+
//#region src/buildVideo.ts
|
|
5
|
+
/**
|
|
6
|
+
* Build the three.js object for a `Video`: a plane textured with an HTML video
|
|
7
|
+
* element. Unlit (`MeshBasicMaterial`) so it stays bright even with the scene
|
|
8
|
+
* lights off. The video element is kept on `userData.video` for the controller
|
|
9
|
+
* to play/pause; `VideoTexture` refreshes itself each frame while playing.
|
|
10
|
+
*/
|
|
11
|
+
function buildVideo(video) {
|
|
12
|
+
const el = document.createElement("video");
|
|
13
|
+
el.src = video.src;
|
|
14
|
+
el.loop = video.loop ?? true;
|
|
15
|
+
el.muted = video.muted ?? true;
|
|
16
|
+
el.playsInline = true;
|
|
17
|
+
el.preload = "auto";
|
|
18
|
+
el.load();
|
|
19
|
+
const texture = new three.VideoTexture(el);
|
|
20
|
+
texture.colorSpace = three.SRGBColorSpace;
|
|
21
|
+
const [width, height] = video.size;
|
|
22
|
+
const mesh = new three.Mesh(new three.PlaneGeometry(width, height), new three.MeshBasicMaterial({ map: texture }));
|
|
23
|
+
mesh.position.set(video.position[0], video.position[1], video.position[2]);
|
|
24
|
+
mesh.rotation.y = video.rotation ?? 0;
|
|
25
|
+
mesh.visible = video.visible ?? true;
|
|
26
|
+
mesh.name = `video:${video.id}`;
|
|
27
|
+
mesh.userData.scenographyId = video.id;
|
|
28
|
+
mesh.userData.video = el;
|
|
29
|
+
if (video.autoplay ?? false) el.play().catch(() => {});
|
|
30
|
+
return mesh;
|
|
31
|
+
}
|
|
32
|
+
//#endregion
|
|
33
|
+
//#region src/VideoController.ts
|
|
34
|
+
/**
|
|
35
|
+
* High-level video control surfaced as `ctx.video`. Works over the live video
|
|
36
|
+
* meshes (queried fresh each call so it survives hot-swaps), driving the
|
|
37
|
+
* underlying HTML video elements by `id`.
|
|
38
|
+
*/
|
|
39
|
+
var VideoController = class {
|
|
40
|
+
getVideos;
|
|
41
|
+
constructor(getVideos) {
|
|
42
|
+
this.getVideos = getVideos;
|
|
43
|
+
}
|
|
44
|
+
element(id) {
|
|
45
|
+
return this.getVideos().get(id)?.userData.video;
|
|
46
|
+
}
|
|
47
|
+
/** Start (or resume) playback of the video with this `id`. */
|
|
48
|
+
play(id) {
|
|
49
|
+
this.element(id)?.play().catch(() => {});
|
|
50
|
+
}
|
|
51
|
+
/** Pause the video with this `id`. */
|
|
52
|
+
pause(id) {
|
|
53
|
+
this.element(id)?.pause();
|
|
54
|
+
}
|
|
55
|
+
/** Show or hide the screen with this `id`. */
|
|
56
|
+
setVisible(id, visible) {
|
|
57
|
+
const mesh = this.getVideos().get(id);
|
|
58
|
+
if (mesh) mesh.visible = visible;
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
//#endregion
|
|
62
|
+
//#region src/plugin.ts
|
|
63
|
+
/**
|
|
64
|
+
* The video plugin: builds each `Video` screen (an HTML video on a plane) and
|
|
65
|
+
* exposes `ctx.video` — a controller that plays/pauses/shows the live screens.
|
|
66
|
+
*/
|
|
67
|
+
const video = () => ({
|
|
68
|
+
data: require_data.videoData,
|
|
69
|
+
build: (definition) => ({ object: buildVideo(definition) }),
|
|
70
|
+
controller: (elements) => ({ api: new VideoController(elements) })
|
|
71
|
+
});
|
|
72
|
+
//#endregion
|
|
73
|
+
exports.VideoController = VideoController;
|
|
74
|
+
exports.buildVideo = buildVideo;
|
|
75
|
+
exports.validateVideo = require_data.validateVideo;
|
|
76
|
+
exports.video = video;
|
|
77
|
+
exports.videoData = require_data.videoData;
|
|
78
|
+
|
|
79
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["VideoTexture","SRGBColorSpace","Mesh","PlaneGeometry","MeshBasicMaterial","videoData"],"sources":["../src/buildVideo.ts","../src/VideoController.ts","../src/plugin.ts"],"sourcesContent":["import { Mesh, MeshBasicMaterial, PlaneGeometry, SRGBColorSpace, VideoTexture, type Object3D } from \"three\";\nimport type { Video } from \"./data\";\n\n/**\n * Build the three.js object for a `Video`: a plane textured with an HTML video\n * element. Unlit (`MeshBasicMaterial`) so it stays bright even with the scene\n * lights off. The video element is kept on `userData.video` for the controller\n * to play/pause; `VideoTexture` refreshes itself each frame while playing.\n */\nexport function buildVideo(video: Video): Object3D {\n const el = document.createElement(\"video\");\n el.src = video.src;\n el.loop = video.loop ?? true;\n el.muted = video.muted ?? true;\n el.playsInline = true;\n el.preload = \"auto\";\n el.load();\n\n const texture = new VideoTexture(el);\n texture.colorSpace = SRGBColorSpace;\n\n const [width, height] = video.size;\n const mesh = new Mesh(new PlaneGeometry(width, height), new MeshBasicMaterial({ map: texture }));\n mesh.position.set(video.position[0], video.position[1], video.position[2]);\n mesh.rotation.y = video.rotation ?? 0;\n mesh.visible = video.visible ?? true;\n mesh.name = `video:${video.id}`;\n mesh.userData.scenographyId = video.id;\n mesh.userData.video = el;\n\n if (video.autoplay ?? false) void el.play().catch(() => {});\n return mesh;\n}\n","import type { VideoApi } from \"@scenography/engine\";\nimport type { Object3D } from \"three\";\n\n/**\n * High-level video control surfaced as `ctx.video`. Works over the live video\n * meshes (queried fresh each call so it survives hot-swaps), driving the\n * underlying HTML video elements by `id`.\n */\nexport class VideoController implements VideoApi {\n private readonly getVideos: () => ReadonlyMap<string, Object3D>;\n\n constructor(getVideos: () => ReadonlyMap<string, Object3D>) {\n this.getVideos = getVideos;\n }\n\n private element(id: string): HTMLVideoElement | undefined {\n return this.getVideos().get(id)?.userData.video as HTMLVideoElement | undefined;\n }\n\n /** Start (or resume) playback of the video with this `id`. */\n play(id: string): void {\n void this.element(id)?.play().catch(() => {});\n }\n\n /** Pause the video with this `id`. */\n pause(id: string): void {\n this.element(id)?.pause();\n }\n\n /** Show or hide the screen with this `id`. */\n setVisible(id: string, visible: boolean): void {\n const mesh = this.getVideos().get(id);\n if (mesh) mesh.visible = visible;\n }\n}\n","import type { EnginePlugin } from \"@scenography/engine\";\n\nimport { buildVideo } from \"./buildVideo\";\nimport { VideoController } from \"./VideoController\";\nimport { videoData, type Video } from \"./data\";\n\n/**\n * The video plugin: builds each `Video` screen (an HTML video on a plane) and\n * exposes `ctx.video` — a controller that plays/pauses/shows the live screens.\n */\nexport const video = (): EnginePlugin<Video> => ({\n data: videoData,\n build: (definition) => ({ object: buildVideo(definition) }),\n controller: (elements) => ({ api: new VideoController(elements) }),\n});\n"],"mappings":";;;;;;;;;;AASA,SAAgB,WAAW,OAAwB;CACjD,MAAM,KAAK,SAAS,cAAc,OAAO;CACzC,GAAG,MAAM,MAAM;CACf,GAAG,OAAO,MAAM,QAAQ;CACxB,GAAG,QAAQ,MAAM,SAAS;CAC1B,GAAG,cAAc;CACjB,GAAG,UAAU;CACb,GAAG,KAAK;CAER,MAAM,UAAU,IAAIA,MAAAA,aAAa,EAAE;CACnC,QAAQ,aAAaC,MAAAA;CAErB,MAAM,CAAC,OAAO,UAAU,MAAM;CAC9B,MAAM,OAAO,IAAIC,MAAAA,KAAK,IAAIC,MAAAA,cAAc,OAAO,MAAM,GAAG,IAAIC,MAAAA,kBAAkB,EAAE,KAAK,QAAQ,CAAC,CAAC;CAC/F,KAAK,SAAS,IAAI,MAAM,SAAS,IAAI,MAAM,SAAS,IAAI,MAAM,SAAS,EAAE;CACzE,KAAK,SAAS,IAAI,MAAM,YAAY;CACpC,KAAK,UAAU,MAAM,WAAW;CAChC,KAAK,OAAO,SAAS,MAAM;CAC3B,KAAK,SAAS,gBAAgB,MAAM;CACpC,KAAK,SAAS,QAAQ;CAEtB,IAAI,MAAM,YAAY,OAAO,GAAQ,KAAK,CAAC,CAAC,YAAY,CAAC,CAAC;CAC1D,OAAO;AACT;;;;;;;;ACxBA,IAAa,kBAAb,MAAiD;CAC/C;CAEA,YAAY,WAAgD;EAC1D,KAAK,YAAY;CACnB;CAEA,QAAgB,IAA0C;EACxD,OAAO,KAAK,UAAU,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,SAAS;CAC5C;;CAGA,KAAK,IAAkB;EACrB,KAAU,QAAQ,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC,YAAY,CAAC,CAAC;CAC9C;;CAGA,MAAM,IAAkB;EACtB,KAAK,QAAQ,EAAE,CAAC,EAAE,MAAM;CAC1B;;CAGA,WAAW,IAAY,SAAwB;EAC7C,MAAM,OAAO,KAAK,UAAU,CAAC,CAAC,IAAI,EAAE;EACpC,IAAI,MAAM,KAAK,UAAU;CAC3B;AACF;;;;;;;ACxBA,MAAa,eAAoC;CAC/C,MAAMC,aAAAA;CACN,QAAQ,gBAAgB,EAAE,QAAQ,WAAW,UAAU,EAAE;CACzD,aAAa,cAAc,EAAE,KAAK,IAAI,gBAAgB,QAAQ,EAAE;AAClE"}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { n as validateVideo, r as Video, t as videoData } from "./index-CtaN02zR.cjs";
|
|
2
|
+
import { EnginePlugin, VideoApi } from "@scenography/engine";
|
|
3
|
+
import { Object3D } from "three";
|
|
4
|
+
|
|
5
|
+
//#region src/plugin.d.ts
|
|
6
|
+
/**
|
|
7
|
+
* The video plugin: builds each `Video` screen (an HTML video on a plane) and
|
|
8
|
+
* exposes `ctx.video` — a controller that plays/pauses/shows the live screens.
|
|
9
|
+
*/
|
|
10
|
+
declare const video: () => EnginePlugin<Video>;
|
|
11
|
+
//#endregion
|
|
12
|
+
//#region src/buildVideo.d.ts
|
|
13
|
+
/**
|
|
14
|
+
* Build the three.js object for a `Video`: a plane textured with an HTML video
|
|
15
|
+
* element. Unlit (`MeshBasicMaterial`) so it stays bright even with the scene
|
|
16
|
+
* lights off. The video element is kept on `userData.video` for the controller
|
|
17
|
+
* to play/pause; `VideoTexture` refreshes itself each frame while playing.
|
|
18
|
+
*/
|
|
19
|
+
declare function buildVideo(video: Video): Object3D;
|
|
20
|
+
//#endregion
|
|
21
|
+
//#region src/VideoController.d.ts
|
|
22
|
+
/**
|
|
23
|
+
* High-level video control surfaced as `ctx.video`. Works over the live video
|
|
24
|
+
* meshes (queried fresh each call so it survives hot-swaps), driving the
|
|
25
|
+
* underlying HTML video elements by `id`.
|
|
26
|
+
*/
|
|
27
|
+
declare class VideoController implements VideoApi {
|
|
28
|
+
private readonly getVideos;
|
|
29
|
+
constructor(getVideos: () => ReadonlyMap<string, Object3D>);
|
|
30
|
+
private element;
|
|
31
|
+
/** Start (or resume) playback of the video with this `id`. */
|
|
32
|
+
play(id: string): void;
|
|
33
|
+
/** Pause the video with this `id`. */
|
|
34
|
+
pause(id: string): void;
|
|
35
|
+
/** Show or hide the screen with this `id`. */
|
|
36
|
+
setVisible(id: string, visible: boolean): void;
|
|
37
|
+
}
|
|
38
|
+
//#endregion
|
|
39
|
+
export { type Video, VideoController, buildVideo, validateVideo, video, videoData };
|
|
40
|
+
//# sourceMappingURL=index.d.cts.map
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { n as validateVideo, r as Video, t as videoData } from "./index-CtaN02zR.mjs";
|
|
2
|
+
import { Object3D } from "three";
|
|
3
|
+
import { EnginePlugin, VideoApi } from "@scenography/engine";
|
|
4
|
+
|
|
5
|
+
//#region src/plugin.d.ts
|
|
6
|
+
/**
|
|
7
|
+
* The video plugin: builds each `Video` screen (an HTML video on a plane) and
|
|
8
|
+
* exposes `ctx.video` — a controller that plays/pauses/shows the live screens.
|
|
9
|
+
*/
|
|
10
|
+
declare const video: () => EnginePlugin<Video>;
|
|
11
|
+
//#endregion
|
|
12
|
+
//#region src/buildVideo.d.ts
|
|
13
|
+
/**
|
|
14
|
+
* Build the three.js object for a `Video`: a plane textured with an HTML video
|
|
15
|
+
* element. Unlit (`MeshBasicMaterial`) so it stays bright even with the scene
|
|
16
|
+
* lights off. The video element is kept on `userData.video` for the controller
|
|
17
|
+
* to play/pause; `VideoTexture` refreshes itself each frame while playing.
|
|
18
|
+
*/
|
|
19
|
+
declare function buildVideo(video: Video): Object3D;
|
|
20
|
+
//#endregion
|
|
21
|
+
//#region src/VideoController.d.ts
|
|
22
|
+
/**
|
|
23
|
+
* High-level video control surfaced as `ctx.video`. Works over the live video
|
|
24
|
+
* meshes (queried fresh each call so it survives hot-swaps), driving the
|
|
25
|
+
* underlying HTML video elements by `id`.
|
|
26
|
+
*/
|
|
27
|
+
declare class VideoController implements VideoApi {
|
|
28
|
+
private readonly getVideos;
|
|
29
|
+
constructor(getVideos: () => ReadonlyMap<string, Object3D>);
|
|
30
|
+
private element;
|
|
31
|
+
/** Start (or resume) playback of the video with this `id`. */
|
|
32
|
+
play(id: string): void;
|
|
33
|
+
/** Pause the video with this `id`. */
|
|
34
|
+
pause(id: string): void;
|
|
35
|
+
/** Show or hide the screen with this `id`. */
|
|
36
|
+
setVisible(id: string, visible: boolean): void;
|
|
37
|
+
}
|
|
38
|
+
//#endregion
|
|
39
|
+
export { type Video, VideoController, buildVideo, validateVideo, video, videoData };
|
|
40
|
+
//# sourceMappingURL=index.d.mts.map
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { n as validateVideo, t as videoData } from "./data-DqD4TXso.mjs";
|
|
2
|
+
import { Mesh, MeshBasicMaterial, PlaneGeometry, SRGBColorSpace, VideoTexture } from "three";
|
|
3
|
+
//#region src/buildVideo.ts
|
|
4
|
+
/**
|
|
5
|
+
* Build the three.js object for a `Video`: a plane textured with an HTML video
|
|
6
|
+
* element. Unlit (`MeshBasicMaterial`) so it stays bright even with the scene
|
|
7
|
+
* lights off. The video element is kept on `userData.video` for the controller
|
|
8
|
+
* to play/pause; `VideoTexture` refreshes itself each frame while playing.
|
|
9
|
+
*/
|
|
10
|
+
function buildVideo(video) {
|
|
11
|
+
const el = document.createElement("video");
|
|
12
|
+
el.src = video.src;
|
|
13
|
+
el.loop = video.loop ?? true;
|
|
14
|
+
el.muted = video.muted ?? true;
|
|
15
|
+
el.playsInline = true;
|
|
16
|
+
el.preload = "auto";
|
|
17
|
+
el.load();
|
|
18
|
+
const texture = new VideoTexture(el);
|
|
19
|
+
texture.colorSpace = SRGBColorSpace;
|
|
20
|
+
const [width, height] = video.size;
|
|
21
|
+
const mesh = new Mesh(new PlaneGeometry(width, height), new MeshBasicMaterial({ map: texture }));
|
|
22
|
+
mesh.position.set(video.position[0], video.position[1], video.position[2]);
|
|
23
|
+
mesh.rotation.y = video.rotation ?? 0;
|
|
24
|
+
mesh.visible = video.visible ?? true;
|
|
25
|
+
mesh.name = `video:${video.id}`;
|
|
26
|
+
mesh.userData.scenographyId = video.id;
|
|
27
|
+
mesh.userData.video = el;
|
|
28
|
+
if (video.autoplay ?? false) el.play().catch(() => {});
|
|
29
|
+
return mesh;
|
|
30
|
+
}
|
|
31
|
+
//#endregion
|
|
32
|
+
//#region src/VideoController.ts
|
|
33
|
+
/**
|
|
34
|
+
* High-level video control surfaced as `ctx.video`. Works over the live video
|
|
35
|
+
* meshes (queried fresh each call so it survives hot-swaps), driving the
|
|
36
|
+
* underlying HTML video elements by `id`.
|
|
37
|
+
*/
|
|
38
|
+
var VideoController = class {
|
|
39
|
+
getVideos;
|
|
40
|
+
constructor(getVideos) {
|
|
41
|
+
this.getVideos = getVideos;
|
|
42
|
+
}
|
|
43
|
+
element(id) {
|
|
44
|
+
return this.getVideos().get(id)?.userData.video;
|
|
45
|
+
}
|
|
46
|
+
/** Start (or resume) playback of the video with this `id`. */
|
|
47
|
+
play(id) {
|
|
48
|
+
this.element(id)?.play().catch(() => {});
|
|
49
|
+
}
|
|
50
|
+
/** Pause the video with this `id`. */
|
|
51
|
+
pause(id) {
|
|
52
|
+
this.element(id)?.pause();
|
|
53
|
+
}
|
|
54
|
+
/** Show or hide the screen with this `id`. */
|
|
55
|
+
setVisible(id, visible) {
|
|
56
|
+
const mesh = this.getVideos().get(id);
|
|
57
|
+
if (mesh) mesh.visible = visible;
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
//#endregion
|
|
61
|
+
//#region src/plugin.ts
|
|
62
|
+
/**
|
|
63
|
+
* The video plugin: builds each `Video` screen (an HTML video on a plane) and
|
|
64
|
+
* exposes `ctx.video` — a controller that plays/pauses/shows the live screens.
|
|
65
|
+
*/
|
|
66
|
+
const video = () => ({
|
|
67
|
+
data: videoData,
|
|
68
|
+
build: (definition) => ({ object: buildVideo(definition) }),
|
|
69
|
+
controller: (elements) => ({ api: new VideoController(elements) })
|
|
70
|
+
});
|
|
71
|
+
//#endregion
|
|
72
|
+
export { VideoController, buildVideo, validateVideo, video, videoData };
|
|
73
|
+
|
|
74
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../src/buildVideo.ts","../src/VideoController.ts","../src/plugin.ts"],"sourcesContent":["import { Mesh, MeshBasicMaterial, PlaneGeometry, SRGBColorSpace, VideoTexture, type Object3D } from \"three\";\nimport type { Video } from \"./data\";\n\n/**\n * Build the three.js object for a `Video`: a plane textured with an HTML video\n * element. Unlit (`MeshBasicMaterial`) so it stays bright even with the scene\n * lights off. The video element is kept on `userData.video` for the controller\n * to play/pause; `VideoTexture` refreshes itself each frame while playing.\n */\nexport function buildVideo(video: Video): Object3D {\n const el = document.createElement(\"video\");\n el.src = video.src;\n el.loop = video.loop ?? true;\n el.muted = video.muted ?? true;\n el.playsInline = true;\n el.preload = \"auto\";\n el.load();\n\n const texture = new VideoTexture(el);\n texture.colorSpace = SRGBColorSpace;\n\n const [width, height] = video.size;\n const mesh = new Mesh(new PlaneGeometry(width, height), new MeshBasicMaterial({ map: texture }));\n mesh.position.set(video.position[0], video.position[1], video.position[2]);\n mesh.rotation.y = video.rotation ?? 0;\n mesh.visible = video.visible ?? true;\n mesh.name = `video:${video.id}`;\n mesh.userData.scenographyId = video.id;\n mesh.userData.video = el;\n\n if (video.autoplay ?? false) void el.play().catch(() => {});\n return mesh;\n}\n","import type { VideoApi } from \"@scenography/engine\";\nimport type { Object3D } from \"three\";\n\n/**\n * High-level video control surfaced as `ctx.video`. Works over the live video\n * meshes (queried fresh each call so it survives hot-swaps), driving the\n * underlying HTML video elements by `id`.\n */\nexport class VideoController implements VideoApi {\n private readonly getVideos: () => ReadonlyMap<string, Object3D>;\n\n constructor(getVideos: () => ReadonlyMap<string, Object3D>) {\n this.getVideos = getVideos;\n }\n\n private element(id: string): HTMLVideoElement | undefined {\n return this.getVideos().get(id)?.userData.video as HTMLVideoElement | undefined;\n }\n\n /** Start (or resume) playback of the video with this `id`. */\n play(id: string): void {\n void this.element(id)?.play().catch(() => {});\n }\n\n /** Pause the video with this `id`. */\n pause(id: string): void {\n this.element(id)?.pause();\n }\n\n /** Show or hide the screen with this `id`. */\n setVisible(id: string, visible: boolean): void {\n const mesh = this.getVideos().get(id);\n if (mesh) mesh.visible = visible;\n }\n}\n","import type { EnginePlugin } from \"@scenography/engine\";\n\nimport { buildVideo } from \"./buildVideo\";\nimport { VideoController } from \"./VideoController\";\nimport { videoData, type Video } from \"./data\";\n\n/**\n * The video plugin: builds each `Video` screen (an HTML video on a plane) and\n * exposes `ctx.video` — a controller that plays/pauses/shows the live screens.\n */\nexport const video = (): EnginePlugin<Video> => ({\n data: videoData,\n build: (definition) => ({ object: buildVideo(definition) }),\n controller: (elements) => ({ api: new VideoController(elements) }),\n});\n"],"mappings":";;;;;;;;;AASA,SAAgB,WAAW,OAAwB;CACjD,MAAM,KAAK,SAAS,cAAc,OAAO;CACzC,GAAG,MAAM,MAAM;CACf,GAAG,OAAO,MAAM,QAAQ;CACxB,GAAG,QAAQ,MAAM,SAAS;CAC1B,GAAG,cAAc;CACjB,GAAG,UAAU;CACb,GAAG,KAAK;CAER,MAAM,UAAU,IAAI,aAAa,EAAE;CACnC,QAAQ,aAAa;CAErB,MAAM,CAAC,OAAO,UAAU,MAAM;CAC9B,MAAM,OAAO,IAAI,KAAK,IAAI,cAAc,OAAO,MAAM,GAAG,IAAI,kBAAkB,EAAE,KAAK,QAAQ,CAAC,CAAC;CAC/F,KAAK,SAAS,IAAI,MAAM,SAAS,IAAI,MAAM,SAAS,IAAI,MAAM,SAAS,EAAE;CACzE,KAAK,SAAS,IAAI,MAAM,YAAY;CACpC,KAAK,UAAU,MAAM,WAAW;CAChC,KAAK,OAAO,SAAS,MAAM;CAC3B,KAAK,SAAS,gBAAgB,MAAM;CACpC,KAAK,SAAS,QAAQ;CAEtB,IAAI,MAAM,YAAY,OAAO,GAAQ,KAAK,CAAC,CAAC,YAAY,CAAC,CAAC;CAC1D,OAAO;AACT;;;;;;;;ACxBA,IAAa,kBAAb,MAAiD;CAC/C;CAEA,YAAY,WAAgD;EAC1D,KAAK,YAAY;CACnB;CAEA,QAAgB,IAA0C;EACxD,OAAO,KAAK,UAAU,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,SAAS;CAC5C;;CAGA,KAAK,IAAkB;EACrB,KAAU,QAAQ,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC,YAAY,CAAC,CAAC;CAC9C;;CAGA,MAAM,IAAkB;EACtB,KAAK,QAAQ,EAAE,CAAC,EAAE,MAAM;CAC1B;;CAGA,WAAW,IAAY,SAAwB;EAC7C,MAAM,OAAO,KAAK,UAAU,CAAC,CAAC,IAAI,EAAE;EACpC,IAAI,MAAM,KAAK,UAAU;CAC3B;AACF;;;;;;;ACxBA,MAAa,eAAoC;CAC/C,MAAM;CACN,QAAQ,gBAAgB,EAAE,QAAQ,WAAW,UAAU,EAAE;CACzD,aAAa,cAAc,EAAE,KAAK,IAAI,gBAAgB,QAAQ,EAAE;AAClE"}
|
package/package.json
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@scenography/plugin-video",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "Video plugin for scenography: video screens (HTML video on a plane) with ctx.video runtime control.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"files": [
|
|
7
|
+
"dist"
|
|
8
|
+
],
|
|
9
|
+
"type": "module",
|
|
10
|
+
"main": "./dist/index.cjs",
|
|
11
|
+
"module": "./dist/index.mjs",
|
|
12
|
+
"types": "./dist/index.d.cts",
|
|
13
|
+
"exports": {
|
|
14
|
+
".": {
|
|
15
|
+
"import": {
|
|
16
|
+
"types": "./dist/index.d.mts",
|
|
17
|
+
"default": "./dist/index.mjs"
|
|
18
|
+
},
|
|
19
|
+
"require": {
|
|
20
|
+
"types": "./dist/index.d.cts",
|
|
21
|
+
"default": "./dist/index.cjs"
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
"./data": {
|
|
25
|
+
"import": {
|
|
26
|
+
"types": "./dist/data.d.mts",
|
|
27
|
+
"default": "./dist/data.mjs"
|
|
28
|
+
},
|
|
29
|
+
"require": {
|
|
30
|
+
"types": "./dist/data.d.cts",
|
|
31
|
+
"default": "./dist/data.cjs"
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
"dependencies": {
|
|
36
|
+
"@scenography/scene": "0.2.0"
|
|
37
|
+
},
|
|
38
|
+
"devDependencies": {
|
|
39
|
+
"@types/three": "^0.160.0",
|
|
40
|
+
"three": "^0.160.0",
|
|
41
|
+
"@scenography/engine": "0.2.0"
|
|
42
|
+
},
|
|
43
|
+
"peerDependencies": {
|
|
44
|
+
"three": ">=0.160.0",
|
|
45
|
+
"@scenography/engine": "0.2.0"
|
|
46
|
+
},
|
|
47
|
+
"scripts": {
|
|
48
|
+
"build": "tsdown",
|
|
49
|
+
"dev": "tsdown --watch",
|
|
50
|
+
"typecheck": "tsc --noEmit"
|
|
51
|
+
}
|
|
52
|
+
}
|