@vosjs/studio-core 0.42.0 → 0.42.2
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.js +51 -51
- package/dist/index.js.map +1 -1
- package/package.json +6 -6
package/dist/index.js
CHANGED
|
@@ -623,7 +623,7 @@ function projectFromArtifact(artifact, videoUrl, opts = {}) {
|
|
|
623
623
|
const coverage = surface === "monitor" || artifact.meta.windowMovedDuringTake || unfocused ? 0 : norm.coverage;
|
|
624
624
|
if (artifact.cursor.length > 0 && coverage < CAPTURE_COVERAGE_MIN) {
|
|
625
625
|
console.warn(
|
|
626
|
-
"[
|
|
626
|
+
"[studio] dropping cursor track \u2014",
|
|
627
627
|
surface === "monitor" ? "entire-screen takes have no cursor effects (untrackable outside browser pages)" : artifact.meta.windowMovedDuringTake ? "window moved/resized during the take" : unfocused ? `browser window focused only ${Math.round((artifact.meta.windowFocusedFrac ?? 0) * 100)}% of the take \u2014 a different window was likely shared` : `coverage ${norm.coverage.toFixed(2)} (wrong surface shared, or unusable capture geometry)`
|
|
628
628
|
);
|
|
629
629
|
}
|
|
@@ -4843,7 +4843,7 @@ var STUDIO_SETUP = `async (ctx) => {
|
|
|
4843
4843
|
// The MediaError rides along: code 4 is an unreadable/unsupported source
|
|
4844
4844
|
// (a dead blob URL, a 404), code 3 a decode failure, code 2 a network
|
|
4845
4845
|
// stall. A bare "failed to load" gave the fleet log nothing to act on.
|
|
4846
|
-
v.onerror = () => rej(new Error('[
|
|
4846
|
+
v.onerror = () => rej(new Error('[studio] video failed to load' + (v.error ? ' (' + v.error.code + (v.error.message ? ': ' + v.error.message : '') + ')' : '')))
|
|
4847
4847
|
v.load()
|
|
4848
4848
|
})
|
|
4849
4849
|
cache.set(src, v)
|
|
@@ -4856,7 +4856,7 @@ var STUDIO_SETUP = `async (ctx) => {
|
|
|
4856
4856
|
const img = new Image()
|
|
4857
4857
|
img.crossOrigin = 'anonymous'
|
|
4858
4858
|
img.onload = () => { cache.set(src, img); res(img) }
|
|
4859
|
-
img.onerror = () => rej(new Error('[
|
|
4859
|
+
img.onerror = () => rej(new Error('[studio] image failed to load'))
|
|
4860
4860
|
img.src = src
|
|
4861
4861
|
})
|
|
4862
4862
|
}
|
|
@@ -4870,7 +4870,7 @@ var STUDIO_SETUP = `async (ctx) => {
|
|
|
4870
4870
|
const faces = ctx.data.overlayFonts || ${JSON.stringify(OVERLAY_FONT_FACES)}
|
|
4871
4871
|
// Mark what SETUP registers, so ON_FRAME's live path (a text overlay
|
|
4872
4872
|
// arriving through SET_DATA) never adds the same face twice.
|
|
4873
|
-
const ofSet = window.
|
|
4873
|
+
const ofSet = window.__vosFontSet || (window.__vosFontSet = {})
|
|
4874
4874
|
const loads = faces.map((f) => {
|
|
4875
4875
|
ofSet[f.family + '|' + f.weight] = 1
|
|
4876
4876
|
const ff = new FontFace(f.family, 'url(' + f.url + ')', { weight: String(f.weight) })
|
|
@@ -4881,7 +4881,7 @@ var STUDIO_SETUP = `async (ctx) => {
|
|
|
4881
4881
|
Promise.all(loads).catch(() => {}),
|
|
4882
4882
|
new Promise((res) => setTimeout(res, 4000)),
|
|
4883
4883
|
])
|
|
4884
|
-
} catch (e) { console.warn('[
|
|
4884
|
+
} catch (e) { console.warn('[studio] overlay fonts failed to load', e) }
|
|
4885
4885
|
}
|
|
4886
4886
|
// An HTML layer arrives as SOURCE, and the picture is built HERE.
|
|
4887
4887
|
//
|
|
@@ -4924,7 +4924,7 @@ var STUDIO_SETUP = `async (ctx) => {
|
|
|
4924
4924
|
// Fail open per URL, and NOT sticky: the layer paints without it now
|
|
4925
4925
|
// and the next build asks again.
|
|
4926
4926
|
faceData.delete(url)
|
|
4927
|
-
console.warn('[
|
|
4927
|
+
console.warn('[studio] html layer ' + what + ' failed to load', url, e)
|
|
4928
4928
|
return ''
|
|
4929
4929
|
})
|
|
4930
4930
|
faceData.set(url, p)
|
|
@@ -4976,7 +4976,7 @@ var STUDIO_SETUP = `async (ctx) => {
|
|
|
4976
4976
|
ns.htmlSafe = true
|
|
4977
4977
|
} catch (e) {
|
|
4978
4978
|
ns.htmlSafe = false
|
|
4979
|
-
console.error('[
|
|
4979
|
+
console.error('[studio] html layers are off: this browser taints a canvas that draws a foreignObject SVG', e)
|
|
4980
4980
|
}
|
|
4981
4981
|
}
|
|
4982
4982
|
// One picture per clip in the cache: the previous key goes when a new
|
|
@@ -4993,7 +4993,7 @@ var STUDIO_SETUP = `async (ctx) => {
|
|
|
4993
4993
|
// recorded on the clip and said at the level a render page forwards.
|
|
4994
4994
|
ns.buildHtmlLayer = (oc, live) => buildHtmlLayer(oc, live).catch((e) => {
|
|
4995
4995
|
ns.htmlErrors[oc.id] = String((e && e.message) || e)
|
|
4996
|
-
console.error('[
|
|
4996
|
+
console.error('[studio] html layer ' + oc.id + ' ' + ns.htmlErrors[oc.id])
|
|
4997
4997
|
})
|
|
4998
4998
|
// The capture contract for a LIVE layer, on ANY anchor. A recording's own
|
|
4999
4999
|
// program installs the settle machinery (pendingDecodes, the wait a
|
|
@@ -5036,7 +5036,7 @@ var STUDIO_SETUP = `async (ctx) => {
|
|
|
5036
5036
|
try {
|
|
5037
5037
|
if (oc.kind === 'image') await loadImage(oc.key)
|
|
5038
5038
|
else await load(oc.key, true)
|
|
5039
|
-
} catch (e) { console.warn('[
|
|
5039
|
+
} catch (e) { console.warn('[studio] overlay media failed to load', oc.key, e) }
|
|
5040
5040
|
}
|
|
5041
5041
|
// GLB object assets (V3b): load via the engine's GLTFLoader addon into a
|
|
5042
5042
|
// shared cache, bbox-NORMALIZED (norm = 1/maxDim) so transform3d.scale means
|
|
@@ -5048,7 +5048,7 @@ var STUDIO_SETUP = `async (ctx) => {
|
|
|
5048
5048
|
if (!oc.asset || oc.asset.kind !== 'gltf' || !oc.asset.key || objCache.has(oc.asset.key)) continue
|
|
5049
5049
|
try {
|
|
5050
5050
|
const GL = ctx.loaders && ctx.loaders.GLTFLoader
|
|
5051
|
-
if (!GL) { console.warn('[
|
|
5051
|
+
if (!GL) { console.warn('[studio] GLTFLoader unavailable'); continue }
|
|
5052
5052
|
const gltf = await new Promise((res, rej) => new GL().load(oc.asset.key, res, undefined, rej))
|
|
5053
5053
|
const box = new ctx.THREE.Box3().setFromObject(gltf.scene)
|
|
5054
5054
|
const size = new ctx.THREE.Vector3()
|
|
@@ -5057,7 +5057,7 @@ var STUDIO_SETUP = `async (ctx) => {
|
|
|
5057
5057
|
box.getCenter(center)
|
|
5058
5058
|
const maxDim = Math.max(size.x, size.y, size.z) || 1
|
|
5059
5059
|
objCache.set(oc.asset.key, { scene: gltf.scene, norm: 1 / maxDim, center: center })
|
|
5060
|
-
} catch (e) { console.warn('[
|
|
5060
|
+
} catch (e) { console.warn('[studio] glb failed to load', oc.asset.key, e) }
|
|
5061
5061
|
}
|
|
5062
5062
|
// 3D-text typefaces: FontLoader JSONs into a shared cache, keyed by
|
|
5063
5063
|
// URL. Awaited here so frame 0 is complete on cold loads (export/chunk
|
|
@@ -5068,10 +5068,10 @@ var STUDIO_SETUP = `async (ctx) => {
|
|
|
5068
5068
|
if (!oc.asset || oc.asset.kind !== 'text3d' || !oc.asset.url || fontCache.has(oc.asset.url)) continue
|
|
5069
5069
|
try {
|
|
5070
5070
|
const FL = ctx.loaders && ctx.loaders.FontLoader
|
|
5071
|
-
if (!FL) { console.warn('[
|
|
5071
|
+
if (!FL) { console.warn('[studio] FontLoader unavailable'); continue }
|
|
5072
5072
|
const font = await new Promise((res, rej) => new FL().load(oc.asset.url, res, undefined, rej))
|
|
5073
5073
|
fontCache.set(oc.asset.url, font)
|
|
5074
|
-
} catch (e) { console.warn('[
|
|
5074
|
+
} catch (e) { console.warn('[studio] typeface failed to load', oc.asset.url, e) }
|
|
5075
5075
|
}
|
|
5076
5076
|
// Audio clips (music/SFX): start decoding into the shared cache now, but
|
|
5077
5077
|
// never hold the first frame for it. Playback starts on a press, so the
|
|
@@ -5096,7 +5096,7 @@ var STUDIO_SETUP = `async (ctx) => {
|
|
|
5096
5096
|
bufs.set(c.key, b)
|
|
5097
5097
|
if (ns.audioSched) ns.audioSched.sig = ''
|
|
5098
5098
|
})
|
|
5099
|
-
.catch((e) => console.warn('[
|
|
5099
|
+
.catch((e) => console.warn('[studio] audio decode failed', c.key, e))
|
|
5100
5100
|
.then(() => pend.delete(c.key))
|
|
5101
5101
|
}
|
|
5102
5102
|
}
|
|
@@ -5218,7 +5218,7 @@ var STUDIO_FRAME = `(ctx, content, dt) => {
|
|
|
5218
5218
|
.then(function (res) { return res.arrayBuffer() })
|
|
5219
5219
|
.then(function (ab) { return actx.decodeAudioData(ab) })
|
|
5220
5220
|
.then(function (b) { bufs.set(cc.key, b); AS.sig = '' })
|
|
5221
|
-
.catch(function (e) { console.warn('[
|
|
5221
|
+
.catch(function (e) { console.warn('[studio] audio decode failed', cc.key, e) })
|
|
5222
5222
|
.then(function () { pend.delete(cc.key) })
|
|
5223
5223
|
})(clips[di])
|
|
5224
5224
|
}
|
|
@@ -5604,7 +5604,7 @@ var STUDIO_FRAME = `(ctx, content, dt) => {
|
|
|
5604
5604
|
// Keyed per window, so SETUP's cold-load faces and repeat frames never
|
|
5605
5605
|
// re-register; fail-open, frames repaint as each face lands.
|
|
5606
5606
|
if (typeof FontFace !== 'undefined') {
|
|
5607
|
-
var ofSet = window.
|
|
5607
|
+
var ofSet = window.__vosFontSet || (window.__vosFontSet = {})
|
|
5608
5608
|
var ofBase = d.overlayFonts || ${JSON.stringify(OVERLAY_FONT_FACES)}
|
|
5609
5609
|
for (var ofi = 0; ofi < ofBase.length; ofi++) {
|
|
5610
5610
|
var ofB = ofBase[ofi]
|
|
@@ -6768,7 +6768,7 @@ var FRAME_STEP_SRC = `
|
|
|
6768
6768
|
// A WebCodecs provider (capture pages) services the frame by PTS at
|
|
6769
6769
|
// decode speed \u2014 no element seek, no 250ms settle cap. The element stays
|
|
6770
6770
|
// paused as the dimension source and fallback.
|
|
6771
|
-
var wcp = vid.
|
|
6771
|
+
var wcp = vid.__vosWc
|
|
6772
6772
|
if (wcp) {
|
|
6773
6773
|
var wcT = Math.min(srcT, wcp.duration || srcT)
|
|
6774
6774
|
if (wcp.req !== wcT) {
|
|
@@ -6799,7 +6799,7 @@ var FRAME_STEP_SRC = `
|
|
|
6799
6799
|
// Capture pages: the loop's frame by PTS from its own provider, like the
|
|
6800
6800
|
// footage. The loop clock only moves forward between wraps, so the walk
|
|
6801
6801
|
// stays sequential and a wrap is one re-seek to the keyframe at 0.
|
|
6802
|
-
var bwc = bgEl.
|
|
6802
|
+
var bwc = bgEl.__vosWc
|
|
6803
6803
|
if (bwc) {
|
|
6804
6804
|
var bwT = Math.min(bgT, bwc.duration || bgT)
|
|
6805
6805
|
if (bwc.req !== bwT) {
|
|
@@ -6846,9 +6846,9 @@ var FRAME_STEP_SRC = `
|
|
|
6846
6846
|
if (fired) return
|
|
6847
6847
|
fired = true
|
|
6848
6848
|
g.removeEventListener('loadeddata', done)
|
|
6849
|
-
if (g.
|
|
6850
|
-
var want = g.
|
|
6851
|
-
g.
|
|
6849
|
+
if (g.__vosWant != null && g.readyState >= 1) {
|
|
6850
|
+
var want = g.__vosWant
|
|
6851
|
+
g.__vosWant = null
|
|
6852
6852
|
var seeked = function () { g.removeEventListener('seeked', seeked); resolve() }
|
|
6853
6853
|
g.addEventListener('seeked', seeked)
|
|
6854
6854
|
setTimeout(seeked, 250)
|
|
@@ -6868,8 +6868,8 @@ var FRAME_STEP_SRC = `
|
|
|
6868
6868
|
return g
|
|
6869
6869
|
}
|
|
6870
6870
|
function stepGhost(g, at) {
|
|
6871
|
-
if (g.readyState >= 1) { g.
|
|
6872
|
-
g.
|
|
6871
|
+
if (g.readyState >= 1) { g.__vosWant = null; stepPaused(g, at); return }
|
|
6872
|
+
g.__vosWant = at
|
|
6873
6873
|
}`;
|
|
6874
6874
|
var SETUP = `async (ctx) => {
|
|
6875
6875
|
;${timelineRuntimeCode2}
|
|
@@ -6897,11 +6897,11 @@ var SETUP = `async (ctx) => {
|
|
|
6897
6897
|
const BG_BLOB_MAX = 64 * 1024 * 1024
|
|
6898
6898
|
const toBlobUrl = async (src) => {
|
|
6899
6899
|
const resp = await fetch(src)
|
|
6900
|
-
if (!resp.ok) throw new Error('[
|
|
6900
|
+
if (!resp.ok) throw new Error('[studio] blob fetch HTTP ' + resp.status)
|
|
6901
6901
|
const len = Number(resp.headers.get('content-length') || 0)
|
|
6902
6902
|
if (len > BLOB_FETCH_MAX) {
|
|
6903
6903
|
try { if (resp.body) await resp.body.cancel() } catch (e) { void e }
|
|
6904
|
-
throw new Error('[
|
|
6904
|
+
throw new Error('[studio] blob fetch over size cap')
|
|
6905
6905
|
}
|
|
6906
6906
|
const fetched = await resp.blob()
|
|
6907
6907
|
// Keep the Blob itself: the WebCodecs provider demuxes the SAME
|
|
@@ -6915,7 +6915,7 @@ var SETUP = `async (ctx) => {
|
|
|
6915
6915
|
let url = src
|
|
6916
6916
|
if (ctx.data.videoFetchMode === 'blob') {
|
|
6917
6917
|
try { url = await toBlobUrl(src) }
|
|
6918
|
-
catch (e) { console.warn('[
|
|
6918
|
+
catch (e) { console.warn('[studio] blob fetch failed, using network src', e) }
|
|
6919
6919
|
}
|
|
6920
6920
|
v = document.createElement('video')
|
|
6921
6921
|
v.src = url
|
|
@@ -6928,7 +6928,7 @@ var SETUP = `async (ctx) => {
|
|
|
6928
6928
|
// The MediaError rides along: code 4 is an unreadable/unsupported source
|
|
6929
6929
|
// (a dead blob URL, a 404), code 3 a decode failure, code 2 a network
|
|
6930
6930
|
// stall. A bare "failed to load" gave the fleet log nothing to act on.
|
|
6931
|
-
v.onerror = () => rej(new Error('[
|
|
6931
|
+
v.onerror = () => rej(new Error('[studio] video failed to load' + (v.error ? ' (' + v.error.code + (v.error.message ? ': ' + v.error.message : '') + ')' : '')))
|
|
6932
6932
|
v.load()
|
|
6933
6933
|
})
|
|
6934
6934
|
cache.set(src, v)
|
|
@@ -6943,7 +6943,7 @@ var SETUP = `async (ctx) => {
|
|
|
6943
6943
|
const img = new Image()
|
|
6944
6944
|
img.crossOrigin = 'anonymous'
|
|
6945
6945
|
img.onload = () => { cache.set(src, img); res(img) }
|
|
6946
|
-
img.onerror = () => rej(new Error('[
|
|
6946
|
+
img.onerror = () => rej(new Error('[studio] image failed to load'))
|
|
6947
6947
|
img.src = src
|
|
6948
6948
|
})
|
|
6949
6949
|
}
|
|
@@ -7019,7 +7019,7 @@ var SETUP = `async (ctx) => {
|
|
|
7019
7019
|
provider.req = t
|
|
7020
7020
|
chain = chain
|
|
7021
7021
|
.then(() => advanceTo(t))
|
|
7022
|
-
.catch((e) => { console.warn('[
|
|
7022
|
+
.catch((e) => { console.warn('[studio] webcodecs frame failed', e) })
|
|
7023
7023
|
return chain
|
|
7024
7024
|
},
|
|
7025
7025
|
// Draw the CURRENT frame into the card. Returns false (element path
|
|
@@ -7054,12 +7054,12 @@ var SETUP = `async (ctx) => {
|
|
|
7054
7054
|
(wcProvider.width === video.videoWidth &&
|
|
7055
7055
|
wcProvider.height === video.videoHeight))
|
|
7056
7056
|
) {
|
|
7057
|
-
video.
|
|
7057
|
+
video.__vosWc = wcProvider
|
|
7058
7058
|
} else if (wcProvider) {
|
|
7059
|
-
console.warn('[
|
|
7059
|
+
console.warn('[studio] webcodecs dims mismatch \u2014 element path keeps the frame')
|
|
7060
7060
|
}
|
|
7061
7061
|
} catch (e) {
|
|
7062
|
-
console.warn('[
|
|
7062
|
+
console.warn('[studio] webcodecs provider unavailable, seeks stay html5', e)
|
|
7063
7063
|
}
|
|
7064
7064
|
}
|
|
7065
7065
|
// The webcam is a separate recording (video-only) drawn as an editable bubble overlay.
|
|
@@ -7078,14 +7078,14 @@ var SETUP = `async (ctx) => {
|
|
|
7078
7078
|
if (!m.isImage && ctx.data.videoDecodeMode === 'webcodecs') {
|
|
7079
7079
|
try {
|
|
7080
7080
|
const wp = await makeWcProvider(m.src)
|
|
7081
|
-
if (wp && (!el.videoWidth || (wp.width === el.videoWidth && wp.height === el.videoHeight))) el.
|
|
7081
|
+
if (wp && (!el.videoWidth || (wp.width === el.videoWidth && wp.height === el.videoHeight))) el.__vosWc = wp
|
|
7082
7082
|
} catch (e) {
|
|
7083
|
-
console.warn('[
|
|
7083
|
+
console.warn('[studio] webcodecs provider unavailable for a media, seeks stay html5', e)
|
|
7084
7084
|
}
|
|
7085
7085
|
}
|
|
7086
7086
|
mediaEls[m.id] = el
|
|
7087
7087
|
} catch (e) {
|
|
7088
|
-
console.warn('[
|
|
7088
|
+
console.warn('[studio] a media failed to load', m.id, e)
|
|
7089
7089
|
}
|
|
7090
7090
|
}
|
|
7091
7091
|
// Background media (frame.backgroundMedia): warm-load so the first paint is
|
|
@@ -7105,7 +7105,7 @@ var SETUP = `async (ctx) => {
|
|
|
7105
7105
|
// into a Blob first when it is small enough (one request instead
|
|
7106
7106
|
// of ranged reads against a CDN). FAIL-OPEN to the element at
|
|
7107
7107
|
// every step, like the footage.
|
|
7108
|
-
if (ctx.data.videoDecodeMode === 'webcodecs' && !bgV.
|
|
7108
|
+
if (ctx.data.videoDecodeMode === 'webcodecs' && !bgV.__vosWc) {
|
|
7109
7109
|
try {
|
|
7110
7110
|
if (!(ns.videoBlobs && ns.videoBlobs.get(bgm.key)) && bgm.key.indexOf('blob:') !== 0 && bgm.key.indexOf('data:') !== 0) {
|
|
7111
7111
|
try {
|
|
@@ -7119,22 +7119,22 @@ var SETUP = `async (ctx) => {
|
|
|
7119
7119
|
} catch (e) { void e }
|
|
7120
7120
|
}
|
|
7121
7121
|
const bgWc = await makeWcProvider(bgm.key)
|
|
7122
|
-
if (bgWc && (!bgV.videoWidth || (bgWc.width === bgV.videoWidth && bgWc.height === bgV.videoHeight))) bgV.
|
|
7122
|
+
if (bgWc && (!bgV.videoWidth || (bgWc.width === bgV.videoWidth && bgWc.height === bgV.videoHeight))) bgV.__vosWc = bgWc
|
|
7123
7123
|
} catch (e) {
|
|
7124
|
-
console.warn('[
|
|
7124
|
+
console.warn('[studio] webcodecs provider unavailable for the background, seeks stay html5', e)
|
|
7125
7125
|
}
|
|
7126
7126
|
}
|
|
7127
7127
|
}
|
|
7128
|
-
} catch (e) { console.warn('[
|
|
7128
|
+
} catch (e) { console.warn('[studio] background media failed to load', e) }
|
|
7129
7129
|
}
|
|
7130
7130
|
// Which path decodes what, for a host's telemetry: 'provider' is the
|
|
7131
7131
|
// sequential WebCodecs walk, 'element' an HTMLVideoElement seek per frame.
|
|
7132
|
-
ns.
|
|
7133
|
-
recording: ctx.data.isImage ? 'none' : video.
|
|
7132
|
+
ns.studioDecode = {
|
|
7133
|
+
recording: ctx.data.isImage ? 'none' : video.__vosWc ? 'provider' : 'element',
|
|
7134
7134
|
backdrop: (function () {
|
|
7135
7135
|
if (!bgm || !bgm.key || bgm.kind === 'image') return 'none'
|
|
7136
7136
|
const bgHit = cache.get(bgm.key)
|
|
7137
|
-
return bgHit && bgHit.
|
|
7137
|
+
return bgHit && bgHit.__vosWc ? 'provider' : 'element'
|
|
7138
7138
|
})(),
|
|
7139
7139
|
}
|
|
7140
7140
|
// Frame prep: a capture harness calls every ns.framePrep hook right after
|
|
@@ -7150,7 +7150,7 @@ var SETUP = `async (ctx) => {
|
|
|
7150
7150
|
// chaining; playback never calls it; a harness without it keeps the
|
|
7151
7151
|
// two-phase loop and stays correct.
|
|
7152
7152
|
ns.framePrep = ns.framePrep || new Map()
|
|
7153
|
-
ns.framePrep.set('
|
|
7153
|
+
ns.framePrep.set('studio.card', (t) => {
|
|
7154
7154
|
if (ns.isPaused === false) return
|
|
7155
7155
|
const d = ctx.data
|
|
7156
7156
|
const TL = globalThis.__vosTimeline
|
|
@@ -7438,17 +7438,17 @@ var ON_FRAME = `(ctx, content, dt) => {
|
|
|
7438
7438
|
// allow="autoplay" so the top frame's activation counts here).
|
|
7439
7439
|
if (!vid.muted && err && err.name === 'NotAllowedError') {
|
|
7440
7440
|
vid.muted = true
|
|
7441
|
-
vid.
|
|
7441
|
+
vid.__vosAutoMuted = true
|
|
7442
7442
|
var p2 = vid.play()
|
|
7443
7443
|
if (p2 && p2.catch) p2.catch(function () {})
|
|
7444
7444
|
}
|
|
7445
7445
|
})
|
|
7446
|
-
} else if (vid.
|
|
7446
|
+
} else if (vid.__vosAutoMuted && d.audioUnlocked) {
|
|
7447
7447
|
// First user gesture happened \u2014 lift the policy fallback. If the
|
|
7448
7448
|
// browser still objects it pauses the element, and the paused branch
|
|
7449
7449
|
// above self-heals (re-mute + resume) on the next frame.
|
|
7450
7450
|
vid.muted = false
|
|
7451
|
-
vid.
|
|
7451
|
+
vid.__vosAutoMuted = false
|
|
7452
7452
|
}
|
|
7453
7453
|
} else {
|
|
7454
7454
|
// The paused step (FRAME_STEP_SRC): the provider by PTS, else the
|
|
@@ -7768,7 +7768,7 @@ var ON_FRAME = `(ctx, content, dt) => {
|
|
|
7768
7768
|
// The loop's provider draws its current sample (paused capture
|
|
7769
7769
|
// pages); false \u21D2 the element (playback, or before the first ask).
|
|
7770
7770
|
try {
|
|
7771
|
-
var bgWcp = !bgIsImg && !playing ? bgEl.
|
|
7771
|
+
var bgWcp = !bgIsImg && !playing ? bgEl.__vosWc : null
|
|
7772
7772
|
if (!(bgWcp && bgWcp.draw(bgC, null, (W - bgDw) / 2 + bgOx, (H - bgDh) / 2 + bgOy, bgDw, bgDh))) {
|
|
7773
7773
|
bgC.drawImage(bgEl, (W - bgDw) / 2 + bgOx, (H - bgDh) / 2 + bgOy, bgDw, bgDh)
|
|
7774
7774
|
}
|
|
@@ -8030,7 +8030,7 @@ var ON_FRAME = `(ctx, content, dt) => {
|
|
|
8030
8030
|
// The provider draws the current sample directly (crop-capable,
|
|
8031
8031
|
// dimension-checked at attach); false \u21D2 element path (pre-first-seek,
|
|
8032
8032
|
// or the provider never attached).
|
|
8033
|
-
var wcp3 = video.
|
|
8033
|
+
var wcp3 = video.__vosWc
|
|
8034
8034
|
if (!(wcp3 && wcp3.draw(c, crp, ceX, ceY, ceW, ceH))) {
|
|
8035
8035
|
if (crp) c.drawImage(video, crp.x, crp.y, crp.w, crp.h, ceX, ceY, ceW, ceH)
|
|
8036
8036
|
else c.drawImage(video, ceX, ceY, ceW, ceH)
|
|
@@ -8589,10 +8589,10 @@ var ON_FRAME = `(ctx, content, dt) => {
|
|
|
8589
8589
|
// gated inside their blocks (dirty-tracking above).
|
|
8590
8590
|
if (card.texture) card.texture.needsUpdate = true
|
|
8591
8591
|
|
|
8592
|
-
// verification hook (no-op unless the harness sets window.
|
|
8592
|
+
// verification hook (no-op unless the harness sets window.__STUDIO_DEBUG__).
|
|
8593
8593
|
// cv = the CARD 2D canvas; bgCv/ovCv are the background/overlay layers (v2).
|
|
8594
|
-
if (typeof window !== 'undefined' && window.
|
|
8595
|
-
window.
|
|
8594
|
+
if (typeof window !== 'undefined' && window.__STUDIO_DEBUG__) {
|
|
8595
|
+
window.__studioDebug = { cv: cv, bgCv: bg.canvas, ovCv: ov.canvas, W: W, H: H, glW: gl && gl.width, glH: gl && gl.height, t: t, canvases: document.querySelectorAll('canvas').length }
|
|
8596
8596
|
}
|
|
8597
8597
|
}`;
|
|
8598
8598
|
function studioLayerData(input, duration, pins) {
|