@twick/2d 0.15.1 → 0.15.3
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/index.cjs +132 -53
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +16 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.js +133 -53
- package/dist/index.js.map +1 -1
- package/editor/editor/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +4 -4
package/dist/index.cjs
CHANGED
|
@@ -5670,8 +5670,8 @@ var Media = class extends Rect {
|
|
|
5670
5670
|
const onError = () => {
|
|
5671
5671
|
const reason = this.getErrorReason(media.error?.code);
|
|
5672
5672
|
const srcValue = this.src();
|
|
5673
|
-
console.
|
|
5674
|
-
console.
|
|
5673
|
+
console.error(`Error loading video: src="${srcValue}", ${reason}`);
|
|
5674
|
+
console.error(`Media element src: "${media.src}"`);
|
|
5675
5675
|
media.removeEventListener("error", onError);
|
|
5676
5676
|
media.removeEventListener("canplay", onCanPlayWrapper);
|
|
5677
5677
|
media.removeEventListener("canplaythrough", onCanPlayWrapper);
|
|
@@ -5690,7 +5690,6 @@ var Media = class extends Rect {
|
|
|
5690
5690
|
return this.awaitCanPlay() || this.view().playbackState() === import_core32.PlaybackState.Rendering;
|
|
5691
5691
|
}
|
|
5692
5692
|
play() {
|
|
5693
|
-
console.log("=== Media.play() called ===");
|
|
5694
5693
|
this.playing(true);
|
|
5695
5694
|
this.schedulePlay();
|
|
5696
5695
|
}
|
|
@@ -5742,12 +5741,14 @@ var Media = class extends Rect {
|
|
|
5742
5741
|
const playPromise = media.play();
|
|
5743
5742
|
if (playPromise !== void 0) {
|
|
5744
5743
|
playPromise.then(() => {
|
|
5745
|
-
console.log("Simple play started successfully");
|
|
5746
5744
|
}).catch((error) => {
|
|
5747
5745
|
if (error.name !== "AbortError") {
|
|
5748
5746
|
console.warn("Error in simple play:", error);
|
|
5749
5747
|
}
|
|
5750
|
-
this.
|
|
5748
|
+
const playbackState = this.view().playbackState();
|
|
5749
|
+
if (playbackState !== import_core32.PlaybackState.Rendering) {
|
|
5750
|
+
this.playing(false);
|
|
5751
|
+
}
|
|
5751
5752
|
});
|
|
5752
5753
|
}
|
|
5753
5754
|
}
|
|
@@ -5757,33 +5758,24 @@ var Media = class extends Rect {
|
|
|
5757
5758
|
}, 10);
|
|
5758
5759
|
}
|
|
5759
5760
|
actuallyPlay(media, timeFunction) {
|
|
5760
|
-
console.log("=== actuallyPlay called ===");
|
|
5761
|
-
console.log("Media element:", media);
|
|
5762
|
-
console.log("Media src:", media.src);
|
|
5763
|
-
console.log("Media paused:", media.paused);
|
|
5764
|
-
console.log("Media readyState:", media.readyState);
|
|
5765
5761
|
if (!this.playing()) {
|
|
5766
|
-
console.log("Playing state is false, aborting actuallyPlay");
|
|
5767
5762
|
return;
|
|
5768
5763
|
}
|
|
5769
5764
|
media.playbackRate = this.playbackRate();
|
|
5770
5765
|
if (media.paused) {
|
|
5771
|
-
console.log("Media is paused, calling play()");
|
|
5772
5766
|
const playPromise = media.play();
|
|
5773
5767
|
if (playPromise !== void 0) {
|
|
5774
5768
|
playPromise.then(() => {
|
|
5775
|
-
console.log("Media play() promise resolved - should be playing now");
|
|
5776
|
-
console.log("Post-play media paused:", media.paused);
|
|
5777
|
-
console.log("Post-play media currentTime:", media.currentTime);
|
|
5778
5769
|
}).catch((error) => {
|
|
5779
5770
|
if (error.name !== "AbortError") {
|
|
5780
5771
|
console.warn("Error playing media:", error);
|
|
5781
5772
|
}
|
|
5782
|
-
this.
|
|
5773
|
+
const playbackState = this.view().playbackState();
|
|
5774
|
+
if (playbackState !== import_core32.PlaybackState.Rendering) {
|
|
5775
|
+
this.playing(false);
|
|
5776
|
+
}
|
|
5783
5777
|
});
|
|
5784
5778
|
}
|
|
5785
|
-
} else {
|
|
5786
|
-
console.log("Media is already playing");
|
|
5787
5779
|
}
|
|
5788
5780
|
const start = timeFunction();
|
|
5789
5781
|
const offset = media.currentTime;
|
|
@@ -5817,11 +5809,13 @@ var Media = class extends Rect {
|
|
|
5817
5809
|
}
|
|
5818
5810
|
autoPlayBasedOnTwick() {
|
|
5819
5811
|
const playbackState = this.view().playbackState();
|
|
5820
|
-
|
|
5821
|
-
|
|
5812
|
+
const shouldBePlaying = playbackState === import_core32.PlaybackState.Playing || playbackState === import_core32.PlaybackState.Presenting || playbackState === import_core32.PlaybackState.Rendering;
|
|
5813
|
+
if (shouldBePlaying && !this.playing()) {
|
|
5814
|
+
if (playbackState === import_core32.PlaybackState.Rendering) {
|
|
5815
|
+
this.playing(true);
|
|
5816
|
+
}
|
|
5822
5817
|
this.play();
|
|
5823
|
-
} else if (
|
|
5824
|
-
console.log("Auto-pausing media playback via pause() method");
|
|
5818
|
+
} else if (!shouldBePlaying && this.playing()) {
|
|
5825
5819
|
this.pause();
|
|
5826
5820
|
}
|
|
5827
5821
|
}
|
|
@@ -10169,6 +10163,57 @@ var Video = class extends Media {
|
|
|
10169
10163
|
this.fileTypeWasDetected = false;
|
|
10170
10164
|
this.lastFrame = null;
|
|
10171
10165
|
}
|
|
10166
|
+
/**
|
|
10167
|
+
* Creates a video element with CORS fallback handling.
|
|
10168
|
+
* First tries with crossOrigin='anonymous', and if that fails due to CORS,
|
|
10169
|
+
* falls back to creating a video without crossOrigin.
|
|
10170
|
+
*/
|
|
10171
|
+
createVideoElement(src, key) {
|
|
10172
|
+
const video = document.createElement("video");
|
|
10173
|
+
video.crossOrigin = "anonymous";
|
|
10174
|
+
if (src && src !== "undefined") {
|
|
10175
|
+
try {
|
|
10176
|
+
const parsedSrc = new URL(src, window.location.origin);
|
|
10177
|
+
if (parsedSrc.pathname.endsWith(".m3u8")) {
|
|
10178
|
+
const hls = new import_hls.default();
|
|
10179
|
+
hls.loadSource(src);
|
|
10180
|
+
hls.attachMedia(video);
|
|
10181
|
+
} else {
|
|
10182
|
+
video.src = src;
|
|
10183
|
+
}
|
|
10184
|
+
} catch (error) {
|
|
10185
|
+
video.src = src;
|
|
10186
|
+
}
|
|
10187
|
+
const errorHandler = () => {
|
|
10188
|
+
const error = video.error;
|
|
10189
|
+
if (error && (error.code === 4 || error.code === 2)) {
|
|
10190
|
+
video.removeEventListener("error", errorHandler);
|
|
10191
|
+
const fallbackKey = `${key}_no_cors`;
|
|
10192
|
+
let fallbackVideo = Video.pool[fallbackKey];
|
|
10193
|
+
if (!fallbackVideo) {
|
|
10194
|
+
fallbackVideo = document.createElement("video");
|
|
10195
|
+
fallbackVideo.crossOrigin = null;
|
|
10196
|
+
try {
|
|
10197
|
+
const parsedSrc = new URL(src, window.location.origin);
|
|
10198
|
+
if (parsedSrc.pathname.endsWith(".m3u8")) {
|
|
10199
|
+
const hls = new import_hls.default();
|
|
10200
|
+
hls.loadSource(src);
|
|
10201
|
+
hls.attachMedia(fallbackVideo);
|
|
10202
|
+
} else {
|
|
10203
|
+
fallbackVideo.src = src;
|
|
10204
|
+
}
|
|
10205
|
+
} catch (err) {
|
|
10206
|
+
fallbackVideo.src = src;
|
|
10207
|
+
}
|
|
10208
|
+
Video.pool[fallbackKey] = fallbackVideo;
|
|
10209
|
+
}
|
|
10210
|
+
Video.pool[key] = fallbackVideo;
|
|
10211
|
+
}
|
|
10212
|
+
};
|
|
10213
|
+
video.addEventListener("error", errorHandler, { once: true });
|
|
10214
|
+
}
|
|
10215
|
+
return video;
|
|
10216
|
+
}
|
|
10172
10217
|
desiredSize() {
|
|
10173
10218
|
const custom = super.desiredSize();
|
|
10174
10219
|
if (custom.x === null && custom.y === null) {
|
|
@@ -10189,44 +10234,55 @@ var Video = class extends Media {
|
|
|
10189
10234
|
fastSeekedMedia() {
|
|
10190
10235
|
return this.fastSeekedVideo();
|
|
10191
10236
|
}
|
|
10237
|
+
/**
|
|
10238
|
+
* Generates a normalized cache key based on the video source URL.
|
|
10239
|
+
* This ensures that all Video elements with the same src share the same HTMLVideoElement.
|
|
10240
|
+
*/
|
|
10241
|
+
getCacheKey(src) {
|
|
10242
|
+
if (!src || src === "undefined") {
|
|
10243
|
+
return `${this.key}/pending`;
|
|
10244
|
+
}
|
|
10245
|
+
try {
|
|
10246
|
+
const url = new URL(src, window.location.origin);
|
|
10247
|
+
return url.href.split("#")[0];
|
|
10248
|
+
} catch {
|
|
10249
|
+
return src;
|
|
10250
|
+
}
|
|
10251
|
+
}
|
|
10192
10252
|
video() {
|
|
10193
10253
|
const src = this.src();
|
|
10194
|
-
const key =
|
|
10254
|
+
const key = this.getCacheKey(src);
|
|
10195
10255
|
let video = Video.pool[key];
|
|
10196
10256
|
if (!video) {
|
|
10197
|
-
video =
|
|
10198
|
-
|
|
10257
|
+
video = this.createVideoElement(src, key);
|
|
10258
|
+
Video.pool[key] = video;
|
|
10259
|
+
} else {
|
|
10199
10260
|
if (src && src !== "undefined") {
|
|
10200
|
-
|
|
10201
|
-
|
|
10202
|
-
|
|
10203
|
-
|
|
10204
|
-
|
|
10205
|
-
|
|
10206
|
-
}
|
|
10261
|
+
const normalizeUrl = (url) => {
|
|
10262
|
+
try {
|
|
10263
|
+
const parsed = new URL(url, window.location.origin);
|
|
10264
|
+
return parsed.href.split("#")[0];
|
|
10265
|
+
} catch {
|
|
10266
|
+
return url;
|
|
10267
|
+
}
|
|
10268
|
+
};
|
|
10269
|
+
const normalizedSrc = normalizeUrl(src);
|
|
10270
|
+
const normalizedVideoSrc = video.src ? normalizeUrl(video.src) : "";
|
|
10271
|
+
if (normalizedVideoSrc !== normalizedSrc) {
|
|
10272
|
+
try {
|
|
10273
|
+
const parsedSrc = new URL(src, window.location.origin);
|
|
10274
|
+
if (parsedSrc.pathname.endsWith(".m3u8")) {
|
|
10275
|
+
const hls = new import_hls.default();
|
|
10276
|
+
hls.loadSource(src);
|
|
10277
|
+
hls.attachMedia(video);
|
|
10278
|
+
} else {
|
|
10279
|
+
video.src = src;
|
|
10280
|
+
}
|
|
10281
|
+
} catch (error) {
|
|
10207
10282
|
video.src = src;
|
|
10208
10283
|
}
|
|
10209
|
-
} catch (error) {
|
|
10210
|
-
video.src = src;
|
|
10211
10284
|
}
|
|
10212
10285
|
}
|
|
10213
|
-
Video.pool[key] = video;
|
|
10214
|
-
} else if (src && src !== "undefined" && video.src !== src) {
|
|
10215
|
-
try {
|
|
10216
|
-
const parsedSrc = new URL(src, window.location.origin);
|
|
10217
|
-
if (parsedSrc.pathname.endsWith(".m3u8")) {
|
|
10218
|
-
const hls = new import_hls.default();
|
|
10219
|
-
hls.loadSource(src);
|
|
10220
|
-
hls.attachMedia(video);
|
|
10221
|
-
} else {
|
|
10222
|
-
video.src = src;
|
|
10223
|
-
}
|
|
10224
|
-
} catch (error) {
|
|
10225
|
-
video.src = src;
|
|
10226
|
-
}
|
|
10227
|
-
delete Video.pool[key];
|
|
10228
|
-
const newKey = `${this.key}/${src}`;
|
|
10229
|
-
Video.pool[newKey] = video;
|
|
10230
10286
|
}
|
|
10231
10287
|
if (!src || src === "undefined") {
|
|
10232
10288
|
import_core59.DependencyContext.collectPromise(
|
|
@@ -10445,6 +10501,11 @@ var Video = class extends Media {
|
|
|
10445
10501
|
);
|
|
10446
10502
|
}
|
|
10447
10503
|
};
|
|
10504
|
+
/**
|
|
10505
|
+
* Static pool of video elements cached by source URL.
|
|
10506
|
+
* Multiple Video components with the same src will share the same HTMLVideoElement
|
|
10507
|
+
* to avoid duplicate network requests and improve performance.
|
|
10508
|
+
*/
|
|
10448
10509
|
Video.pool = {};
|
|
10449
10510
|
Video.imageCommunication = !import_meta3.hot ? null : new ImageCommunication();
|
|
10450
10511
|
__decorateClass([
|
|
@@ -10607,8 +10668,26 @@ var Scene2D = class extends import_core60.GeneratorScene {
|
|
|
10607
10668
|
}
|
|
10608
10669
|
}
|
|
10609
10670
|
getMediaAssets() {
|
|
10610
|
-
const
|
|
10611
|
-
const
|
|
10671
|
+
const playbackState = this.playback.state;
|
|
10672
|
+
const isRendering = playbackState === import_core60.PlaybackState.Rendering;
|
|
10673
|
+
const allVideos = Array.from(this.registeredNodes.values()).filter((node) => node instanceof Video);
|
|
10674
|
+
const allAudios = Array.from(this.registeredNodes.values()).filter((node) => node instanceof Audio);
|
|
10675
|
+
if (isRendering) {
|
|
10676
|
+
allVideos.forEach((video) => {
|
|
10677
|
+
const src = video.src();
|
|
10678
|
+
if (src && src !== "undefined" && !video.isPlaying()) {
|
|
10679
|
+
video.playing(true);
|
|
10680
|
+
}
|
|
10681
|
+
});
|
|
10682
|
+
allAudios.forEach((audio) => {
|
|
10683
|
+
const src = audio.src();
|
|
10684
|
+
if (src && src !== "undefined" && !audio.isPlaying()) {
|
|
10685
|
+
audio.playing(true);
|
|
10686
|
+
}
|
|
10687
|
+
});
|
|
10688
|
+
}
|
|
10689
|
+
const playingVideos = allVideos.filter((video) => video.isPlaying());
|
|
10690
|
+
const playingAudios = allAudios.filter((audio) => audio.isPlaying());
|
|
10612
10691
|
const returnObjects = [];
|
|
10613
10692
|
returnObjects.push(
|
|
10614
10693
|
...playingVideos.map((vid) => ({
|