@onmark/cli 0.4.0 → 0.5.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/onmark-release.json +47 -47
- package/package.json +4 -4
- package/packages/authoring/dist/src/presentation.js +127 -6
- package/packages/bundler/dist/src/authored_html.d.ts +2 -0
- package/packages/bundler/dist/src/authored_html.js +30 -0
- package/packages/bundler/dist/src/command.js +10 -6
- package/packages/bundler/dist/src/generated/bundle-manifest.d.ts +4 -5
- package/packages/bundler/dist/src/generated/bundle-manifest.js +1 -0
- package/packages/bundler/dist/src/presentation.d.ts +1 -1
- package/packages/bundler/dist/src/presentation.js +13 -2
- package/packages/runtime/dist/src/generated/browser-request.d.ts +5 -1
- package/packages/runtime/dist/src/generated/browser-response.d.ts +46 -1
- package/packages/runtime/dist/src/generated/bundle-layout.d.ts +1 -1
- package/packages/runtime/dist/src/generated/bundle-layout.js +1 -0
- package/packages/runtime/dist/src/generated/runtime-contract.d.ts +3 -1
- package/packages/runtime/dist/src/generated/runtime-contract.js +3 -1
- package/packages/runtime/dist/src/generated/validators.js +1172 -465
- package/packages/runtime/dist/src/index.d.ts +3 -3
- package/packages/runtime/dist/src/index.js +1 -1
- package/packages/runtime/dist/src/presentation.d.ts +8 -3
- package/packages/runtime/dist/src/presentation.js +97 -7
- package/packages/runtime/dist/src/session.d.ts +7 -3
- package/packages/runtime/dist/src/session.js +17 -9
- package/packages/runtime/dist/src/types.d.ts +2 -1
package/onmark-release.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 1,
|
|
3
3
|
"packageName": "@onmark/cli",
|
|
4
|
-
"version": "0.
|
|
5
|
-
"sourceRevision": "
|
|
4
|
+
"version": "0.5.0",
|
|
5
|
+
"sourceRevision": "770428f38a704d4f08eb117e64d52fc37a164931",
|
|
6
6
|
"files": [
|
|
7
7
|
{
|
|
8
8
|
"path": "LICENSE",
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
{
|
|
18
18
|
"path": "package.json",
|
|
19
19
|
"bytes": 1406,
|
|
20
|
-
"sha256": "
|
|
20
|
+
"sha256": "91721649e92466ab8a096460c959146c113b6f3d18a9f8f2617b3b2af6af023d"
|
|
21
21
|
},
|
|
22
22
|
{
|
|
23
23
|
"path": "packages/authoring/dist/src/frame-motion.d.ts",
|
|
@@ -66,8 +66,8 @@
|
|
|
66
66
|
},
|
|
67
67
|
{
|
|
68
68
|
"path": "packages/authoring/dist/src/presentation.js",
|
|
69
|
-
"bytes":
|
|
70
|
-
"sha256": "
|
|
69
|
+
"bytes": 14927,
|
|
70
|
+
"sha256": "0a47ca310dce4c37db3a241cb63301d504aa8d767063a395aa520d519e14a874"
|
|
71
71
|
},
|
|
72
72
|
{
|
|
73
73
|
"path": "packages/authoring/dist/src/resource.d.ts",
|
|
@@ -101,13 +101,13 @@
|
|
|
101
101
|
},
|
|
102
102
|
{
|
|
103
103
|
"path": "packages/bundler/dist/src/authored_html.d.ts",
|
|
104
|
-
"bytes":
|
|
105
|
-
"sha256": "
|
|
104
|
+
"bytes": 2278,
|
|
105
|
+
"sha256": "7b40cb7d424b01b0543caf97ac9ed50ca68d94ddf969de7219b5c9c9a29f674c"
|
|
106
106
|
},
|
|
107
107
|
{
|
|
108
108
|
"path": "packages/bundler/dist/src/authored_html.js",
|
|
109
|
-
"bytes":
|
|
110
|
-
"sha256": "
|
|
109
|
+
"bytes": 17153,
|
|
110
|
+
"sha256": "841d2fc962b65d7f5cfafd4805eac28990d76f15cf298173ca1d7ac424a2480e"
|
|
111
111
|
},
|
|
112
112
|
{
|
|
113
113
|
"path": "packages/bundler/dist/src/bundle_projection.d.ts",
|
|
@@ -126,18 +126,18 @@
|
|
|
126
126
|
},
|
|
127
127
|
{
|
|
128
128
|
"path": "packages/bundler/dist/src/command.js",
|
|
129
|
-
"bytes":
|
|
130
|
-
"sha256": "
|
|
129
|
+
"bytes": 6086,
|
|
130
|
+
"sha256": "39a4302c67457825502e2ad525309f3cf26ebb2bf2f957aa4b5d36bd391b53ab"
|
|
131
131
|
},
|
|
132
132
|
{
|
|
133
133
|
"path": "packages/bundler/dist/src/generated/bundle-manifest.d.ts",
|
|
134
|
-
"bytes":
|
|
135
|
-
"sha256": "
|
|
134
|
+
"bytes": 2500,
|
|
135
|
+
"sha256": "8599570ed61765e2f6e167c637f8ca7b2d83bf1c8fc44242c62aa0e2178ec290"
|
|
136
136
|
},
|
|
137
137
|
{
|
|
138
138
|
"path": "packages/bundler/dist/src/generated/bundle-manifest.js",
|
|
139
|
-
"bytes":
|
|
140
|
-
"sha256": "
|
|
139
|
+
"bytes": 646,
|
|
140
|
+
"sha256": "49a7197dfca225e5ab1a296562b6dd9cbf50bd101eefd8650994085b367a50c0"
|
|
141
141
|
},
|
|
142
142
|
{
|
|
143
143
|
"path": "packages/bundler/dist/src/generated/bundle-projection-validator.d.ts",
|
|
@@ -191,13 +191,13 @@
|
|
|
191
191
|
},
|
|
192
192
|
{
|
|
193
193
|
"path": "packages/bundler/dist/src/presentation.d.ts",
|
|
194
|
-
"bytes":
|
|
195
|
-
"sha256": "
|
|
194
|
+
"bytes": 2312,
|
|
195
|
+
"sha256": "b15d3a4c69baccfd6ed56628348dfba180ea698f77993b20b4a249572d7e0cb8"
|
|
196
196
|
},
|
|
197
197
|
{
|
|
198
198
|
"path": "packages/bundler/dist/src/presentation.js",
|
|
199
|
-
"bytes":
|
|
200
|
-
"sha256": "
|
|
199
|
+
"bytes": 20567,
|
|
200
|
+
"sha256": "62524b69029d27972163c19d3bb87832dbb7c1cb6e4b465715f4375e2ed84fca"
|
|
201
201
|
},
|
|
202
202
|
{
|
|
203
203
|
"path": "packages/launcher/dist/desktop-release.json",
|
|
@@ -306,8 +306,8 @@
|
|
|
306
306
|
},
|
|
307
307
|
{
|
|
308
308
|
"path": "packages/runtime/dist/src/generated/browser-request.d.ts",
|
|
309
|
-
"bytes":
|
|
310
|
-
"sha256": "
|
|
309
|
+
"bytes": 5010,
|
|
310
|
+
"sha256": "9bd56a97a68aa2a48c4ef94c104a77e18d4b6b95e4444d76fb461468f54640ce"
|
|
311
311
|
},
|
|
312
312
|
{
|
|
313
313
|
"path": "packages/runtime/dist/src/generated/browser-request.js",
|
|
@@ -316,8 +316,8 @@
|
|
|
316
316
|
},
|
|
317
317
|
{
|
|
318
318
|
"path": "packages/runtime/dist/src/generated/browser-response.d.ts",
|
|
319
|
-
"bytes":
|
|
320
|
-
"sha256": "
|
|
319
|
+
"bytes": 2540,
|
|
320
|
+
"sha256": "f0345c35a41f7f09961fa7df181a30d991116769e9ecb28dd0627e76a0a20034"
|
|
321
321
|
},
|
|
322
322
|
{
|
|
323
323
|
"path": "packages/runtime/dist/src/generated/browser-response.js",
|
|
@@ -326,13 +326,13 @@
|
|
|
326
326
|
},
|
|
327
327
|
{
|
|
328
328
|
"path": "packages/runtime/dist/src/generated/bundle-layout.d.ts",
|
|
329
|
-
"bytes":
|
|
330
|
-
"sha256": "
|
|
329
|
+
"bytes": 660,
|
|
330
|
+
"sha256": "213d9166593e39cedf85489b1415834fe95b6d6b95ec00ef0a56c9f10a37c736"
|
|
331
331
|
},
|
|
332
332
|
{
|
|
333
333
|
"path": "packages/runtime/dist/src/generated/bundle-layout.js",
|
|
334
|
-
"bytes":
|
|
335
|
-
"sha256": "
|
|
334
|
+
"bytes": 480,
|
|
335
|
+
"sha256": "f22f9910f25b67d0953fca16488b97531dcefb273938c7ed0fcf9d04552be90e"
|
|
336
336
|
},
|
|
337
337
|
{
|
|
338
338
|
"path": "packages/runtime/dist/src/generated/codec.d.ts",
|
|
@@ -346,13 +346,13 @@
|
|
|
346
346
|
},
|
|
347
347
|
{
|
|
348
348
|
"path": "packages/runtime/dist/src/generated/runtime-contract.d.ts",
|
|
349
|
-
"bytes":
|
|
350
|
-
"sha256": "
|
|
349
|
+
"bytes": 609,
|
|
350
|
+
"sha256": "ba1fac50be3c9494935fbc5d31c1e3037934e2d6dd1ca3adfe3d692575f68d27"
|
|
351
351
|
},
|
|
352
352
|
{
|
|
353
353
|
"path": "packages/runtime/dist/src/generated/runtime-contract.js",
|
|
354
|
-
"bytes":
|
|
355
|
-
"sha256": "
|
|
354
|
+
"bytes": 604,
|
|
355
|
+
"sha256": "3cc8116cc4d37c92643c672ef313bed7aa32ac466aeb8724e9563548a6d981ce"
|
|
356
356
|
},
|
|
357
357
|
{
|
|
358
358
|
"path": "packages/runtime/dist/src/generated/validators.d.ts",
|
|
@@ -361,8 +361,8 @@
|
|
|
361
361
|
},
|
|
362
362
|
{
|
|
363
363
|
"path": "packages/runtime/dist/src/generated/validators.js",
|
|
364
|
-
"bytes":
|
|
365
|
-
"sha256": "
|
|
364
|
+
"bytes": 274203,
|
|
365
|
+
"sha256": "8e1309412309eeda69cd27a8b3a88935cdb8a8b61d0e6776a0a4ac472039e930"
|
|
366
366
|
},
|
|
367
367
|
{
|
|
368
368
|
"path": "packages/runtime/dist/src/host.d.ts",
|
|
@@ -376,13 +376,13 @@
|
|
|
376
376
|
},
|
|
377
377
|
{
|
|
378
378
|
"path": "packages/runtime/dist/src/index.d.ts",
|
|
379
|
-
"bytes":
|
|
380
|
-
"sha256": "
|
|
379
|
+
"bytes": 1895,
|
|
380
|
+
"sha256": "5faebc8e4726ec5261e174a55811536991ae0cf42135e0f43e5fb67e9df77eba"
|
|
381
381
|
},
|
|
382
382
|
{
|
|
383
383
|
"path": "packages/runtime/dist/src/index.js",
|
|
384
|
-
"bytes":
|
|
385
|
-
"sha256": "
|
|
384
|
+
"bytes": 1152,
|
|
385
|
+
"sha256": "10bb00b68b1aba0106334606c72a68227c2dbc9f997aaf99afd14c0502b18872"
|
|
386
386
|
},
|
|
387
387
|
{
|
|
388
388
|
"path": "packages/runtime/dist/src/media.d.ts",
|
|
@@ -396,13 +396,13 @@
|
|
|
396
396
|
},
|
|
397
397
|
{
|
|
398
398
|
"path": "packages/runtime/dist/src/presentation.d.ts",
|
|
399
|
-
"bytes":
|
|
400
|
-
"sha256": "
|
|
399
|
+
"bytes": 3943,
|
|
400
|
+
"sha256": "9f2abf95bc614f0a41a42c52f2563574afa24b126c1b266983cc72e1a0f83ee1"
|
|
401
401
|
},
|
|
402
402
|
{
|
|
403
403
|
"path": "packages/runtime/dist/src/presentation.js",
|
|
404
|
-
"bytes":
|
|
405
|
-
"sha256": "
|
|
404
|
+
"bytes": 17755,
|
|
405
|
+
"sha256": "de785ba109f6cf446d211cb05387f5d42d406a61f9cb9c5e38925fbd9c4bccbe"
|
|
406
406
|
},
|
|
407
407
|
{
|
|
408
408
|
"path": "packages/runtime/dist/src/resource.d.ts",
|
|
@@ -416,18 +416,18 @@
|
|
|
416
416
|
},
|
|
417
417
|
{
|
|
418
418
|
"path": "packages/runtime/dist/src/session.d.ts",
|
|
419
|
-
"bytes":
|
|
420
|
-
"sha256": "
|
|
419
|
+
"bytes": 2298,
|
|
420
|
+
"sha256": "28b12b59ac2e042ae6e571f861b5b70dec0779a08b6ad1cf8897b262bdbc51db"
|
|
421
421
|
},
|
|
422
422
|
{
|
|
423
423
|
"path": "packages/runtime/dist/src/session.js",
|
|
424
|
-
"bytes":
|
|
425
|
-
"sha256": "
|
|
424
|
+
"bytes": 20533,
|
|
425
|
+
"sha256": "6383f8ff8fda51e0c51b5c20d736c45bf9d36cc76dfb41bb87588ff0b72654b6"
|
|
426
426
|
},
|
|
427
427
|
{
|
|
428
428
|
"path": "packages/runtime/dist/src/types.d.ts",
|
|
429
|
-
"bytes":
|
|
430
|
-
"sha256": "
|
|
429
|
+
"bytes": 753,
|
|
430
|
+
"sha256": "20d1e1c41b5ed7ac43341b928a6ba331dd73fcf2fea2fe8534f0c523233358ff"
|
|
431
431
|
},
|
|
432
432
|
{
|
|
433
433
|
"path": "packages/runtime/dist/src/types.js",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@onmark/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "Screenplay-first deterministic browser video compiler",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -45,8 +45,8 @@
|
|
|
45
45
|
"yauzl": "3.4.0"
|
|
46
46
|
},
|
|
47
47
|
"optionalDependencies": {
|
|
48
|
-
"@onmark/cli-darwin-arm64": "0.
|
|
49
|
-
"@onmark/cli-linux-x64": "0.
|
|
50
|
-
"@onmark/cli-win32-x64": "0.
|
|
48
|
+
"@onmark/cli-darwin-arm64": "0.5.0",
|
|
49
|
+
"@onmark/cli-linux-x64": "0.5.0",
|
|
50
|
+
"@onmark/cli-win32-x64": "0.5.0"
|
|
51
51
|
}
|
|
52
52
|
}
|
|
@@ -90,15 +90,10 @@ class AuthoredDocument {
|
|
|
90
90
|
}
|
|
91
91
|
bindVideo(placement) {
|
|
92
92
|
const element = requiredNode(this.#nodeIndex(), placement.node, "video", ELEMENTS.video);
|
|
93
|
-
const bound = bindElement(element, placement.node);
|
|
94
93
|
element.muted = true;
|
|
95
94
|
element.playsInline = true;
|
|
96
95
|
this.#record("video", element, placement.node, placement.interval);
|
|
97
|
-
return
|
|
98
|
-
...bound,
|
|
99
|
-
element,
|
|
100
|
-
source: this.#videoSource(placement),
|
|
101
|
-
};
|
|
96
|
+
return bindVideoElement(element, placement.node, this.#videoSource(placement));
|
|
102
97
|
}
|
|
103
98
|
bindTransition(placement) {
|
|
104
99
|
const nodes = this.#nodeIndex();
|
|
@@ -238,6 +233,132 @@ function bindElement(element, node, release) {
|
|
|
238
233
|
},
|
|
239
234
|
};
|
|
240
235
|
}
|
|
236
|
+
function bindVideoElement(element, node, source) {
|
|
237
|
+
const bound = bindElement(element, node);
|
|
238
|
+
const authoredVisibility = element.style.visibility;
|
|
239
|
+
let layoutVisible = false;
|
|
240
|
+
return {
|
|
241
|
+
element,
|
|
242
|
+
source,
|
|
243
|
+
setVisible: bound.setVisible,
|
|
244
|
+
setLayoutVisible(visible) {
|
|
245
|
+
if (visible) {
|
|
246
|
+
element.style.visibility = "hidden";
|
|
247
|
+
bound.setVisible(true);
|
|
248
|
+
}
|
|
249
|
+
else {
|
|
250
|
+
bound.setVisible(false);
|
|
251
|
+
element.style.visibility = authoredVisibility;
|
|
252
|
+
}
|
|
253
|
+
layoutVisible = visible;
|
|
254
|
+
},
|
|
255
|
+
measureLayout() {
|
|
256
|
+
if (!layoutVisible) {
|
|
257
|
+
throw new Error("video layout requires a visible layout-only element");
|
|
258
|
+
}
|
|
259
|
+
return measureVideoLayout(element, node.nodeId);
|
|
260
|
+
},
|
|
261
|
+
dispose() {
|
|
262
|
+
bound.setVisible(false);
|
|
263
|
+
element.style.visibility = authoredVisibility;
|
|
264
|
+
bound.dispose();
|
|
265
|
+
},
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
function measureVideoLayout(element, nodeId) {
|
|
269
|
+
requireStaticVideoStyle(element);
|
|
270
|
+
const rectangle = pixelRectangle(element.getBoundingClientRect());
|
|
271
|
+
const style = getComputedStyle(element);
|
|
272
|
+
return Object.freeze({
|
|
273
|
+
nodeId,
|
|
274
|
+
objectFit: objectFit(style.objectFit),
|
|
275
|
+
objectPosition: objectPosition(style.objectPosition),
|
|
276
|
+
rectangle,
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
function requireStaticVideoStyle(element) {
|
|
280
|
+
const style = getComputedStyle(element);
|
|
281
|
+
const unsupported = [
|
|
282
|
+
["border-radius", style.borderRadius, "0px"],
|
|
283
|
+
["filter", style.filter, "none"],
|
|
284
|
+
["mix-blend-mode", style.mixBlendMode, "normal"],
|
|
285
|
+
["opacity", style.opacity, "1"],
|
|
286
|
+
["transform", style.transform, "none"],
|
|
287
|
+
];
|
|
288
|
+
for (const [name, actual, expected] of unsupported) {
|
|
289
|
+
if (actual !== expected) {
|
|
290
|
+
throw new Error(`layout-only video requires ${name}: ${expected}, found ${actual}`);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
for (const name of [
|
|
294
|
+
"borderBottomWidth",
|
|
295
|
+
"borderLeftWidth",
|
|
296
|
+
"borderRightWidth",
|
|
297
|
+
"borderTopWidth",
|
|
298
|
+
"paddingBottom",
|
|
299
|
+
"paddingLeft",
|
|
300
|
+
"paddingRight",
|
|
301
|
+
"paddingTop",
|
|
302
|
+
]) {
|
|
303
|
+
if (style[name] !== "0px") {
|
|
304
|
+
throw new Error(`layout-only video requires ${cssName(name)}: 0`);
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
if (style.clipPath !== "none") {
|
|
308
|
+
throw new Error("layout-only video requires clip-path: none");
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
function pixelRectangle(rectangle) {
|
|
312
|
+
const values = [rectangle.x, rectangle.y, rectangle.width, rectangle.height];
|
|
313
|
+
if (devicePixelRatio !== 1 ||
|
|
314
|
+
!values.every(Number.isSafeInteger) ||
|
|
315
|
+
rectangle.x < 0 ||
|
|
316
|
+
rectangle.y < 0 ||
|
|
317
|
+
rectangle.width <= 0 ||
|
|
318
|
+
rectangle.height <= 0 ||
|
|
319
|
+
rectangle.right > document.documentElement.clientWidth ||
|
|
320
|
+
rectangle.bottom > document.documentElement.clientHeight) {
|
|
321
|
+
throw new Error("layout-only video requires a positive, pixel-aligned viewport rectangle");
|
|
322
|
+
}
|
|
323
|
+
return Object.freeze({
|
|
324
|
+
height: rectangle.height,
|
|
325
|
+
width: rectangle.width,
|
|
326
|
+
x: rectangle.x,
|
|
327
|
+
y: rectangle.y,
|
|
328
|
+
});
|
|
329
|
+
}
|
|
330
|
+
function objectFit(value) {
|
|
331
|
+
if (value === "fill" || value === "contain" || value === "cover") {
|
|
332
|
+
return value;
|
|
333
|
+
}
|
|
334
|
+
throw new Error(`layout-only video does not support object-fit: ${value}`);
|
|
335
|
+
}
|
|
336
|
+
function objectPosition(value) {
|
|
337
|
+
const [x, y, ...rest] = value.trim().split(/\s+/u);
|
|
338
|
+
if (x === undefined || y === undefined || rest.length > 0) {
|
|
339
|
+
throw new Error("layout-only video requires two percentage positions");
|
|
340
|
+
}
|
|
341
|
+
return Object.freeze({
|
|
342
|
+
x: percentageMillionths(x),
|
|
343
|
+
y: percentageMillionths(y),
|
|
344
|
+
});
|
|
345
|
+
}
|
|
346
|
+
function percentageMillionths(value) {
|
|
347
|
+
const match = /^(?<whole>[0-9]{1,3})(?:\.(?<fraction>[0-9]{1,4}))?%$/u.exec(value);
|
|
348
|
+
if (match?.groups === undefined) {
|
|
349
|
+
throw new Error("layout-only video object-position must use exact percentages");
|
|
350
|
+
}
|
|
351
|
+
const whole = Number(match.groups["whole"]);
|
|
352
|
+
const fraction = Number((match.groups["fraction"] ?? "").padEnd(4, "0"));
|
|
353
|
+
const millionths = whole * 10_000 + fraction;
|
|
354
|
+
if (millionths > 1_000_000) {
|
|
355
|
+
throw new Error("layout-only video object-position must lie between 0% and 100%");
|
|
356
|
+
}
|
|
357
|
+
return millionths;
|
|
358
|
+
}
|
|
359
|
+
function cssName(value) {
|
|
360
|
+
return value.replace(/[A-Z]/gu, (character) => `-${character.toLowerCase()}`);
|
|
361
|
+
}
|
|
241
362
|
function requireAuthoredId(element, node) {
|
|
242
363
|
const expected = node.authoredId ?? "";
|
|
243
364
|
if (element.id !== expected) {
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
import type { PresentationVisualCapability } from "../../../runtime/dist/src/index.js";
|
|
1
2
|
import { type HtmlImageResource } from "./html_image.js";
|
|
2
3
|
/** Authored document bytes and optional inline module prepared for esbuild. */
|
|
3
4
|
export interface AuthoredHtml {
|
|
4
5
|
readonly document: string;
|
|
5
6
|
readonly motion: string | undefined;
|
|
7
|
+
readonly visualCapability: PresentationVisualCapability | undefined;
|
|
6
8
|
readonly resources: readonly HtmlImageResource[];
|
|
7
9
|
readonly shots: readonly AuthoredHtmlShot[];
|
|
8
10
|
readonly regionStructure: AuthoredHtmlRegionStructure;
|
|
@@ -6,6 +6,7 @@ import { parse } from "parse5";
|
|
|
6
6
|
import { freezeHtmlImages } from "./html_image.js";
|
|
7
7
|
const MAX_HTML_BYTES = 8 * 1024 * 1024;
|
|
8
8
|
const MOTION_ATTRIBUTE = "data-om-motion";
|
|
9
|
+
const VISUAL_CAPABILITY_META = "onmark:visual-capability";
|
|
9
10
|
const RUNTIME_SCRIPT = '<script type="module" src="./presentation.js"></script>';
|
|
10
11
|
/** Invalid or unreadable authored HTML at the Node bundling boundary. */
|
|
11
12
|
export class AuthoredHtmlError extends Error {
|
|
@@ -18,6 +19,7 @@ export class AuthoredHtmlError extends Error {
|
|
|
18
19
|
export async function readAuthoredHtml(path, maxOutputBytes, resolveDirectory) {
|
|
19
20
|
const absolute = resolve(path);
|
|
20
21
|
const source = await readBoundedSource(absolute);
|
|
22
|
+
const visualCapability = declaredVisualCapability(parseDocument(source));
|
|
21
23
|
const directory = resolveDirectory === undefined
|
|
22
24
|
? dirname(absolute)
|
|
23
25
|
: resolve(resolveDirectory);
|
|
@@ -28,6 +30,7 @@ export async function readAuthoredHtml(path, maxOutputBytes, resolveDirectory) {
|
|
|
28
30
|
...extracted,
|
|
29
31
|
resources: frozen.resources,
|
|
30
32
|
resolveDirectory: directory,
|
|
33
|
+
visualCapability,
|
|
31
34
|
});
|
|
32
35
|
}
|
|
33
36
|
// ── Bounded input
|
|
@@ -267,6 +270,33 @@ function collectScripts(node) {
|
|
|
267
270
|
});
|
|
268
271
|
return scripts;
|
|
269
272
|
}
|
|
273
|
+
function declaredVisualCapability(document) {
|
|
274
|
+
const declarations = [];
|
|
275
|
+
visit(document, (element) => {
|
|
276
|
+
if (element.tagName !== "meta") {
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
const attributes = new Map(element.attrs.map(({ name, value }) => [name, value]));
|
|
280
|
+
if (attributes.get("name") === VISUAL_CAPABILITY_META) {
|
|
281
|
+
declarations.push(attributes.get("content") ?? "");
|
|
282
|
+
}
|
|
283
|
+
});
|
|
284
|
+
if (declarations.length > 1) {
|
|
285
|
+
throw new AuthoredHtmlError(`authored HTML may contain at most one ${VISUAL_CAPABILITY_META} declaration`);
|
|
286
|
+
}
|
|
287
|
+
const [declaration] = declarations;
|
|
288
|
+
if (declaration === undefined) {
|
|
289
|
+
return undefined;
|
|
290
|
+
}
|
|
291
|
+
switch (declaration) {
|
|
292
|
+
case "browserComposite":
|
|
293
|
+
case "separableBackdrop":
|
|
294
|
+
case "separableOverlay":
|
|
295
|
+
return declaration;
|
|
296
|
+
default:
|
|
297
|
+
throw new AuthoredHtmlError(`${VISUAL_CAPABILITY_META} must be browserComposite, separableBackdrop, or separableOverlay`);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
270
300
|
function findElement(node, name) {
|
|
271
301
|
const pending = [node];
|
|
272
302
|
while (pending.length > 0) {
|
|
@@ -14,7 +14,7 @@ const USAGE = [
|
|
|
14
14
|
" --max-output-bytes <bytes>",
|
|
15
15
|
" --frame-behavior <perFrame|placementBounded>",
|
|
16
16
|
" --temporal-capability <sequential|randomAccess>",
|
|
17
|
-
" --visual-capability <browserComposite|separableOverlay>",
|
|
17
|
+
" [--visual-capability <browserComposite|separableBackdrop|separableOverlay>]",
|
|
18
18
|
"",
|
|
19
19
|
].join("\n");
|
|
20
20
|
// ── Execution ──
|
|
@@ -45,12 +45,12 @@ async function parseArguments(arguments_) {
|
|
|
45
45
|
const maxOutputBytes = parseByteLimit(oneValue(values["max-output-bytes"], "--max-output-bytes"));
|
|
46
46
|
const frameBehavior = parseFrameBehavior(oneValue(values["frame-behavior"], "--frame-behavior"));
|
|
47
47
|
const temporalCapability = parseTemporalCapability(oneValue(values["temporal-capability"], "--temporal-capability"));
|
|
48
|
-
const visualCapability =
|
|
48
|
+
const visualCapability = optionalVisualCapability(values["visual-capability"]);
|
|
49
49
|
const controls = {
|
|
50
50
|
frameBehavior,
|
|
51
51
|
maxOutputBytes,
|
|
52
52
|
outputDirectory,
|
|
53
|
-
visualCapability,
|
|
53
|
+
...visualCapability,
|
|
54
54
|
};
|
|
55
55
|
const common = {
|
|
56
56
|
...controls,
|
|
@@ -107,12 +107,16 @@ function parseTemporalCapability(value) {
|
|
|
107
107
|
}
|
|
108
108
|
throw configuration("--temporal-capability must be sequential or randomAccess");
|
|
109
109
|
}
|
|
110
|
-
function
|
|
110
|
+
function optionalVisualCapability(values) {
|
|
111
|
+
if (values === undefined) {
|
|
112
|
+
return {};
|
|
113
|
+
}
|
|
114
|
+
const value = oneValue(values, "--visual-capability");
|
|
111
115
|
const capability = BUNDLE_VISUAL_CAPABILITIES.find((candidate) => candidate === value);
|
|
112
116
|
if (capability !== undefined) {
|
|
113
|
-
return capability;
|
|
117
|
+
return { visualCapability: capability };
|
|
114
118
|
}
|
|
115
|
-
throw configuration("--visual-capability must be browserComposite or separableOverlay");
|
|
119
|
+
throw configuration("--visual-capability must be browserComposite, separableBackdrop, or separableOverlay");
|
|
116
120
|
}
|
|
117
121
|
function parseFrameBehavior(value) {
|
|
118
122
|
const behavior = BUNDLE_FRAME_BEHAVIORS.find((candidate) => candidate === value);
|
|
@@ -25,11 +25,10 @@ export type BundleVersion = 1;
|
|
|
25
25
|
/**
|
|
26
26
|
* Proven relationship between browser presentation pixels and primary media.
|
|
27
27
|
*
|
|
28
|
-
* Unknown presentation code requires `BrowserComposite`. A separable
|
|
29
|
-
*
|
|
30
|
-
* independent of the primary video beneath it.
|
|
28
|
+
* Unknown presentation code requires `BrowserComposite`. A separable layer
|
|
29
|
+
* explicitly limits browser ownership to one side of native media.
|
|
31
30
|
*/
|
|
32
|
-
export type PresentationVisualCapability = "browserComposite" | "separableOverlay";
|
|
31
|
+
export type PresentationVisualCapability = "browserComposite" | "separableBackdrop" | "separableOverlay";
|
|
33
32
|
/**
|
|
34
33
|
* Stable description of one immutable presentation artifact.
|
|
35
34
|
*/
|
|
@@ -57,7 +56,7 @@ export interface BundleFile {
|
|
|
57
56
|
}
|
|
58
57
|
export declare const BUNDLE_VERSION: 1;
|
|
59
58
|
export declare const BUNDLE_TEMPORAL_CAPABILITIES: readonly ["sequential", "randomAccess"];
|
|
60
|
-
export declare const BUNDLE_VISUAL_CAPABILITIES: readonly ["browserComposite", "separableOverlay"];
|
|
59
|
+
export declare const BUNDLE_VISUAL_CAPABILITIES: readonly ["browserComposite", "separableBackdrop", "separableOverlay"];
|
|
61
60
|
export declare const BUNDLE_FRAME_BEHAVIORS: readonly ["perFrame", "placementBounded"];
|
|
62
61
|
export declare const BUNDLE_ENTRY_POINT: "index.html";
|
|
63
62
|
export declare const BUNDLE_MANIFEST_FILE: "manifest.json";
|
|
@@ -15,7 +15,7 @@ interface BundleControls {
|
|
|
15
15
|
readonly resolveDirectory?: string;
|
|
16
16
|
readonly outputDirectory: string;
|
|
17
17
|
readonly maxOutputBytes: number;
|
|
18
|
-
readonly visualCapability
|
|
18
|
+
readonly visualCapability?: PresentationVisualCapability;
|
|
19
19
|
readonly frameBehavior: PresentationFrameBehavior;
|
|
20
20
|
}
|
|
21
21
|
/** Explicit inputs for one authored HTML document. */
|
|
@@ -64,6 +64,7 @@ export async function bundlePresentation(options) {
|
|
|
64
64
|
return bundle(Object.freeze({
|
|
65
65
|
...controls,
|
|
66
66
|
html: Object.freeze({ ...html }),
|
|
67
|
+
visualCapability: resolveVisualCapability(controls.visualCapability, html.visualCapability),
|
|
67
68
|
}));
|
|
68
69
|
}
|
|
69
70
|
async function bundle(input) {
|
|
@@ -110,7 +111,9 @@ function snapshotControls(options) {
|
|
|
110
111
|
throw new BundleError("configuration", "maximum output bytes must be a positive safe integer");
|
|
111
112
|
}
|
|
112
113
|
const temporalCapability = validateTemporalCapability(options.temporalCapability);
|
|
113
|
-
const visualCapability =
|
|
114
|
+
const visualCapability = options.visualCapability === undefined
|
|
115
|
+
? undefined
|
|
116
|
+
: validateVisualCapability(options.visualCapability);
|
|
114
117
|
const frameBehavior = validateFrameBehavior(options.frameBehavior);
|
|
115
118
|
if (frameBehavior === "placementBounded" &&
|
|
116
119
|
temporalCapability !== "randomAccess") {
|
|
@@ -177,7 +180,15 @@ function validateVisualCapability(capability) {
|
|
|
177
180
|
if (admitted !== undefined) {
|
|
178
181
|
return admitted;
|
|
179
182
|
}
|
|
180
|
-
throw new BundleError("configuration", "visual capability must be browserComposite or separableOverlay");
|
|
183
|
+
throw new BundleError("configuration", "visual capability must be browserComposite, separableBackdrop, or separableOverlay");
|
|
184
|
+
}
|
|
185
|
+
function resolveVisualCapability(configured, authored) {
|
|
186
|
+
if (configured !== undefined &&
|
|
187
|
+
authored !== undefined &&
|
|
188
|
+
configured !== authored) {
|
|
189
|
+
throw new BundleError("configuration", "configured and authored visual capabilities disagree");
|
|
190
|
+
}
|
|
191
|
+
return configured ?? authored ?? "browserComposite";
|
|
181
192
|
}
|
|
182
193
|
function validateFrameBehavior(behavior) {
|
|
183
194
|
const admitted = BUNDLE_FRAME_BEHAVIORS.find((candidate) => candidate === behavior);
|
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
* Closed commands understood by the browser runtime.
|
|
3
3
|
*/
|
|
4
4
|
export type BrowserCommand = {
|
|
5
|
+
/**
|
|
6
|
+
* Browser responsibility for primary-media elements.
|
|
7
|
+
*/
|
|
8
|
+
mediaMode: "decoded" | "omitted" | "layoutOnly";
|
|
5
9
|
plan: BrowserPlan;
|
|
6
10
|
type: "load";
|
|
7
11
|
} | {
|
|
@@ -66,7 +70,7 @@ export type RequestId = number;
|
|
|
66
70
|
/**
|
|
67
71
|
* Version of the native-to-browser message contract.
|
|
68
72
|
*/
|
|
69
|
-
export type ProtocolVersion =
|
|
73
|
+
export type ProtocolVersion = 5;
|
|
70
74
|
/**
|
|
71
75
|
* One versioned command sent from the native executor to the browser.
|
|
72
76
|
*/
|
|
@@ -8,6 +8,7 @@ export type BrowserEvent = {
|
|
|
8
8
|
* Frame at which preparation completed.
|
|
9
9
|
*/
|
|
10
10
|
evaluationStart: number;
|
|
11
|
+
mediaLayout: BrowserMediaLayout;
|
|
11
12
|
type: "prepared";
|
|
12
13
|
} | {
|
|
13
14
|
/**
|
|
@@ -40,6 +41,25 @@ export type BrowserEvent = {
|
|
|
40
41
|
} | {
|
|
41
42
|
type: "disposed";
|
|
42
43
|
};
|
|
44
|
+
/**
|
|
45
|
+
* Browser identity for one Timeline element or imported caption.
|
|
46
|
+
*
|
|
47
|
+
* IDs form dense renderable-semantic preorder within one Browser Plan.
|
|
48
|
+
*
|
|
49
|
+
* Authored IDs, rather than this unit-local key, retain cross-projection
|
|
50
|
+
* semantic identity.
|
|
51
|
+
*/
|
|
52
|
+
export type BrowserNodeId = number;
|
|
53
|
+
/**
|
|
54
|
+
* Closed CSS object-fit subset admitted by native media.
|
|
55
|
+
*/
|
|
56
|
+
export type BrowserObjectFit = "fill" | "contain" | "cover";
|
|
57
|
+
/**
|
|
58
|
+
* Exact static media layout observed by the browser.
|
|
59
|
+
*
|
|
60
|
+
* @maxItems 16
|
|
61
|
+
*/
|
|
62
|
+
export type BrowserMediaLayout = BrowserMediaPlacement[];
|
|
43
63
|
/**
|
|
44
64
|
* Correlation identity shared by one request and its response events.
|
|
45
65
|
*/
|
|
@@ -47,7 +67,7 @@ export type RequestId = number;
|
|
|
47
67
|
/**
|
|
48
68
|
* Version of the native-to-browser message contract.
|
|
49
69
|
*/
|
|
50
|
-
export type ProtocolVersion =
|
|
70
|
+
export type ProtocolVersion = 5;
|
|
51
71
|
/**
|
|
52
72
|
* One versioned event returned by the browser runtime.
|
|
53
73
|
*/
|
|
@@ -56,3 +76,28 @@ export interface BrowserResponse {
|
|
|
56
76
|
requestId: RequestId;
|
|
57
77
|
version: ProtocolVersion;
|
|
58
78
|
}
|
|
79
|
+
/**
|
|
80
|
+
* One video element's static, axis-aligned browser layout.
|
|
81
|
+
*/
|
|
82
|
+
export interface BrowserMediaPlacement {
|
|
83
|
+
nodeId: BrowserNodeId;
|
|
84
|
+
objectFit: BrowserObjectFit;
|
|
85
|
+
objectPosition: BrowserObjectPosition;
|
|
86
|
+
rectangle: BrowserPixelRectangle;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Fixed-point CSS object-position, where one million represents 100%.
|
|
90
|
+
*/
|
|
91
|
+
export interface BrowserObjectPosition {
|
|
92
|
+
x: number;
|
|
93
|
+
y: number;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Positive pixel rectangle relative to the output viewport.
|
|
97
|
+
*/
|
|
98
|
+
export interface BrowserPixelRectangle {
|
|
99
|
+
height: number;
|
|
100
|
+
width: number;
|
|
101
|
+
x: number;
|
|
102
|
+
y: number;
|
|
103
|
+
}
|