@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.
@@ -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
@@ -0,0 +1,4 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_data = require("./data-BJdJij0e.cjs");
3
+ exports.validateVideo = require_data.validateVideo;
4
+ exports.videoData = require_data.videoData;
@@ -0,0 +1,2 @@
1
+ import { n as validateVideo, r as Video, t as videoData } from "./index-CtaN02zR.cjs";
2
+ export { type Video, validateVideo, videoData };
@@ -0,0 +1,2 @@
1
+ import { n as validateVideo, r as Video, t as videoData } from "./index-CtaN02zR.mjs";
2
+ export { type Video, validateVideo, videoData };
package/dist/data.mjs ADDED
@@ -0,0 +1,2 @@
1
+ import { n as validateVideo, t as videoData } from "./data-DqD4TXso.mjs";
2
+ export { validateVideo, videoData };
@@ -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"}
@@ -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
@@ -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
+ }