@markdy/renderer-dom 0.6.0 → 0.7.1
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.d.ts +16 -0
- package/dist/index.js +206 -63
- package/package.json +7 -4
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { SceneAST, ParseWarning } from '@markdy/core';
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* @markdy/renderer-dom — Player
|
|
3
5
|
*
|
|
@@ -19,10 +21,18 @@
|
|
|
19
21
|
* each actor's before-phase state falls through to the inline style we set,
|
|
20
22
|
* which gives correct initial positions and opacity values.
|
|
21
23
|
*/
|
|
24
|
+
|
|
22
25
|
interface PlayerOptions {
|
|
23
26
|
container: HTMLElement;
|
|
24
27
|
code: string;
|
|
25
28
|
assets?: Record<string, string>;
|
|
29
|
+
/**
|
|
30
|
+
* Host-resolved ASTs for `import "<path>" as <ns>` statements. When
|
|
31
|
+
* provided, the namespaces' `vars`, `defs`, and `seqs` merge into the
|
|
32
|
+
* parsed scene under `ns.<name>`. Unresolved namespaces emit a soft
|
|
33
|
+
* `import-unresolved` warning.
|
|
34
|
+
*/
|
|
35
|
+
imports?: Record<string, SceneAST>;
|
|
26
36
|
autoplay?: boolean;
|
|
27
37
|
/** Loop the animation when it reaches the end. Defaults to true. */
|
|
28
38
|
loop?: boolean;
|
|
@@ -30,6 +40,12 @@ interface PlayerOptions {
|
|
|
30
40
|
copyright?: boolean;
|
|
31
41
|
/** Show a rainbow progress bar around the viewport border. Defaults to true. */
|
|
32
42
|
progressBar?: boolean;
|
|
43
|
+
/**
|
|
44
|
+
* Invoked once per soft `ParseWarning` emitted by the parser — e.g. unknown
|
|
45
|
+
* actions, unknown modifier keys, unresolved imports. Defaults to `console.warn`.
|
|
46
|
+
* Pass a no-op to silence; pass a custom collector to surface warnings in a UI.
|
|
47
|
+
*/
|
|
48
|
+
onWarning?: (warning: ParseWarning) => void;
|
|
33
49
|
}
|
|
34
50
|
interface Player {
|
|
35
51
|
play(): void;
|
package/dist/index.js
CHANGED
|
@@ -14,6 +14,9 @@ function stateFrom(def) {
|
|
|
14
14
|
function tx(s) {
|
|
15
15
|
return `translate(${s.x}px, ${s.y}px) scale(${s.scale}) rotate(${s.rotate}deg)`;
|
|
16
16
|
}
|
|
17
|
+
function txCaption(s) {
|
|
18
|
+
return `translate(calc(${s.x}px - 50%), calc(${s.y}px - 50%)) scale(${s.scale}) rotate(${s.rotate}deg)`;
|
|
19
|
+
}
|
|
17
20
|
var EASE_MAP = {
|
|
18
21
|
linear: "linear",
|
|
19
22
|
in: "ease-in",
|
|
@@ -335,6 +338,31 @@ function createActorEl(name, def, assetDefs, assetOverrides) {
|
|
|
335
338
|
el = div;
|
|
336
339
|
break;
|
|
337
340
|
}
|
|
341
|
+
case "caption": {
|
|
342
|
+
const div = document.createElement("div");
|
|
343
|
+
div.textContent = def.args[0] ?? "";
|
|
344
|
+
div.dataset.markdyCaption = def.anchor ?? "top";
|
|
345
|
+
Object.assign(div.style, {
|
|
346
|
+
fontSize: `${def.size ?? 32}px`,
|
|
347
|
+
fontFamily: "system-ui, -apple-system, sans-serif",
|
|
348
|
+
fontWeight: "700",
|
|
349
|
+
whiteSpace: "nowrap",
|
|
350
|
+
textAlign: "center",
|
|
351
|
+
lineHeight: "1.1",
|
|
352
|
+
padding: "6px 14px",
|
|
353
|
+
borderRadius: "4px",
|
|
354
|
+
background: "rgba(0, 0, 0, 0.55)",
|
|
355
|
+
color: "#fff",
|
|
356
|
+
textShadow: "0 2px 6px rgba(0, 0, 0, 0.45)",
|
|
357
|
+
userSelect: "none",
|
|
358
|
+
pointerEvents: "none"
|
|
359
|
+
// Center the caption on its (x, y) point (x = sceneWidth/2).
|
|
360
|
+
// We combine translate-centering with the actor transform in the
|
|
361
|
+
// dataset below so the player can re-apply on state changes.
|
|
362
|
+
});
|
|
363
|
+
el = div;
|
|
364
|
+
break;
|
|
365
|
+
}
|
|
338
366
|
case "figure": {
|
|
339
367
|
el = createFigureEl(def);
|
|
340
368
|
break;
|
|
@@ -354,9 +382,10 @@ function createActorEl(name, def, assetDefs, assetOverrides) {
|
|
|
354
382
|
el.style.left = "0";
|
|
355
383
|
el.style.top = "0";
|
|
356
384
|
el.style.transformOrigin = "center center";
|
|
357
|
-
el.style.transform = tx(stateFrom(def));
|
|
385
|
+
el.style.transform = def.type === "caption" ? txCaption(stateFrom(def)) : tx(stateFrom(def));
|
|
358
386
|
el.style.opacity = String(def.opacity ?? 1);
|
|
359
387
|
if (def.z !== void 0) el.style.zIndex = String(def.z);
|
|
388
|
+
else if (def.type === "caption") el.style.zIndex = "100";
|
|
360
389
|
return el;
|
|
361
390
|
}
|
|
362
391
|
|
|
@@ -380,12 +409,15 @@ function buildAnimations(ast, actorEls, scene, assetOverrides, faceSwaps) {
|
|
|
380
409
|
for (const [name, def] of Object.entries(ast.actors)) {
|
|
381
410
|
states.set(name, stateFrom(def));
|
|
382
411
|
}
|
|
412
|
+
const captionActors = /* @__PURE__ */ new Set();
|
|
413
|
+
for (const [name, def] of Object.entries(ast.actors)) {
|
|
414
|
+
if (def.type === "caption") captionActors.add(name);
|
|
415
|
+
}
|
|
416
|
+
const txFor = (actorName) => captionActors.has(actorName) ? txCaption : tx;
|
|
383
417
|
const events = [...ast.events].sort((a, b) => a.time - b.time);
|
|
384
|
-
preInitInlineStyles(ast, actorEls, states, events);
|
|
418
|
+
preInitInlineStyles(ast, actorEls, states, events, txFor);
|
|
419
|
+
const cameraState = freshCameraState();
|
|
385
420
|
for (const ev of events) {
|
|
386
|
-
const el = actorEls.get(ev.actor);
|
|
387
|
-
const s = states.get(ev.actor);
|
|
388
|
-
if (!el || !s) continue;
|
|
389
421
|
const delayMs = ev.time * 1e3;
|
|
390
422
|
const durMs = Math.max(
|
|
391
423
|
1,
|
|
@@ -398,13 +430,39 @@ function buildAnimations(ast, actorEls, scene, assetOverrides, faceSwaps) {
|
|
|
398
430
|
fill: "forwards",
|
|
399
431
|
easing
|
|
400
432
|
};
|
|
401
|
-
|
|
433
|
+
if (ev.actor === "camera") {
|
|
434
|
+
buildCameraAction(ev, scene, ast, baseOpts, anims, cameraState);
|
|
435
|
+
continue;
|
|
436
|
+
}
|
|
437
|
+
const el = actorEls.get(ev.actor);
|
|
438
|
+
const s = states.get(ev.actor);
|
|
439
|
+
if (!el || !s) continue;
|
|
440
|
+
buildAction(ev, el, s, baseOpts, delayMs, durMs, ast, states, scene, assetOverrides, faceSwaps, anims, txFor(ev.actor));
|
|
402
441
|
}
|
|
403
442
|
return anims;
|
|
404
443
|
}
|
|
405
|
-
function
|
|
444
|
+
function offscreenState(s, direction, sceneWidth, sceneHeight) {
|
|
445
|
+
const out = { ...s };
|
|
446
|
+
switch (direction) {
|
|
447
|
+
case "left":
|
|
448
|
+
out.x = -sceneWidth * 1.1;
|
|
449
|
+
break;
|
|
450
|
+
case "right":
|
|
451
|
+
out.x = sceneWidth * 2.1;
|
|
452
|
+
break;
|
|
453
|
+
case "top":
|
|
454
|
+
out.y = -sceneHeight * 1.1;
|
|
455
|
+
break;
|
|
456
|
+
case "bottom":
|
|
457
|
+
out.y = sceneHeight * 2.1;
|
|
458
|
+
break;
|
|
459
|
+
}
|
|
460
|
+
return out;
|
|
461
|
+
}
|
|
462
|
+
function preInitInlineStyles(ast, actorEls, states, events, txFor) {
|
|
406
463
|
const firstEventByActor = /* @__PURE__ */ new Map();
|
|
407
464
|
for (const ev of events) {
|
|
465
|
+
if (ev.actor === "camera") continue;
|
|
408
466
|
if (!firstEventByActor.has(ev.actor)) firstEventByActor.set(ev.actor, ev);
|
|
409
467
|
}
|
|
410
468
|
for (const [name, def] of Object.entries(ast.actors)) {
|
|
@@ -412,31 +470,78 @@ function preInitInlineStyles(ast, actorEls, states, events) {
|
|
|
412
470
|
const s = states.get(name);
|
|
413
471
|
if (!el || !s) continue;
|
|
414
472
|
const firstEv = firstEventByActor.get(name);
|
|
473
|
+
const txFn = txFor(name);
|
|
415
474
|
if (firstEv?.action === "enter") {
|
|
416
475
|
const from = String(firstEv.params.from ?? "left");
|
|
417
|
-
const offscreen =
|
|
418
|
-
|
|
419
|
-
case "left":
|
|
420
|
-
offscreen.x = -ast.meta.width * 1.1;
|
|
421
|
-
break;
|
|
422
|
-
case "right":
|
|
423
|
-
offscreen.x = ast.meta.width * 2.1;
|
|
424
|
-
break;
|
|
425
|
-
case "top":
|
|
426
|
-
offscreen.y = -ast.meta.height * 1.1;
|
|
427
|
-
break;
|
|
428
|
-
case "bottom":
|
|
429
|
-
offscreen.y = ast.meta.height * 2.1;
|
|
430
|
-
break;
|
|
431
|
-
}
|
|
432
|
-
el.style.transform = tx(offscreen);
|
|
476
|
+
const offscreen = offscreenState(s, from, ast.meta.width, ast.meta.height);
|
|
477
|
+
el.style.transform = txFn(offscreen);
|
|
433
478
|
}
|
|
434
479
|
if (firstEv?.action === "fade_in" && (def.opacity === void 0 || def.opacity > 0)) {
|
|
435
480
|
el.style.opacity = "0";
|
|
436
481
|
}
|
|
437
482
|
}
|
|
438
483
|
}
|
|
439
|
-
function
|
|
484
|
+
function freshCameraState() {
|
|
485
|
+
return { x: 0, y: 0, zoom: 1 };
|
|
486
|
+
}
|
|
487
|
+
function cameraTx(s) {
|
|
488
|
+
return `translate(${-s.x}px, ${-s.y}px) scale(${s.zoom})`;
|
|
489
|
+
}
|
|
490
|
+
function buildCameraAction(ev, scene, ast, baseOpts, anims, cameraState) {
|
|
491
|
+
const s = cameraState;
|
|
492
|
+
switch (ev.action) {
|
|
493
|
+
case "pan": {
|
|
494
|
+
const to = ev.params.to;
|
|
495
|
+
if (!to) break;
|
|
496
|
+
const sceneW = ast.meta.width;
|
|
497
|
+
const sceneH = ast.meta.height;
|
|
498
|
+
const targetX = to[0] - sceneW / 2;
|
|
499
|
+
const targetY = to[1] - sceneH / 2;
|
|
500
|
+
const next = { ...s, x: targetX, y: targetY };
|
|
501
|
+
anims.push(
|
|
502
|
+
scene.animate(
|
|
503
|
+
[{ transform: cameraTx(s) }, { transform: cameraTx(next) }],
|
|
504
|
+
baseOpts
|
|
505
|
+
)
|
|
506
|
+
);
|
|
507
|
+
s.x = next.x;
|
|
508
|
+
s.y = next.y;
|
|
509
|
+
break;
|
|
510
|
+
}
|
|
511
|
+
case "zoom": {
|
|
512
|
+
const to = typeof ev.params.to === "number" ? ev.params.to : s.zoom;
|
|
513
|
+
const next = { ...s, zoom: to };
|
|
514
|
+
anims.push(
|
|
515
|
+
scene.animate(
|
|
516
|
+
[{ transform: cameraTx(s) }, { transform: cameraTx(next) }],
|
|
517
|
+
baseOpts
|
|
518
|
+
)
|
|
519
|
+
);
|
|
520
|
+
s.zoom = next.zoom;
|
|
521
|
+
break;
|
|
522
|
+
}
|
|
523
|
+
case "shake": {
|
|
524
|
+
const mag = typeof ev.params.intensity === "number" ? ev.params.intensity : 8;
|
|
525
|
+
anims.push(
|
|
526
|
+
scene.animate(
|
|
527
|
+
[
|
|
528
|
+
{ transform: cameraTx(s), offset: 0 },
|
|
529
|
+
{ transform: cameraTx({ ...s, x: s.x - mag, y: s.y - mag * 0.4 }), offset: 0.15 },
|
|
530
|
+
{ transform: cameraTx({ ...s, x: s.x + mag, y: s.y + mag * 0.4 }), offset: 0.35 },
|
|
531
|
+
{ transform: cameraTx({ ...s, x: s.x - mag * 0.6, y: s.y + mag * 0.3 }), offset: 0.55 },
|
|
532
|
+
{ transform: cameraTx({ ...s, x: s.x + mag * 0.5, y: s.y - mag * 0.3 }), offset: 0.75 },
|
|
533
|
+
{ transform: cameraTx(s), offset: 1 }
|
|
534
|
+
],
|
|
535
|
+
{ ...baseOpts, easing: "linear" }
|
|
536
|
+
)
|
|
537
|
+
);
|
|
538
|
+
break;
|
|
539
|
+
}
|
|
540
|
+
default:
|
|
541
|
+
break;
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
function buildAction(ev, el, s, baseOpts, delayMs, durMs, ast, states, scene, assetOverrides, faceSwaps, anims, txFn) {
|
|
440
545
|
switch (ev.action) {
|
|
441
546
|
// ── move ────────────────────────────────────────────────────────────────
|
|
442
547
|
case "move": {
|
|
@@ -445,7 +550,7 @@ function buildAction(ev, el, s, baseOpts, delayMs, durMs, ast, states, scene, as
|
|
|
445
550
|
const toY = toArr?.[1] ?? s.y;
|
|
446
551
|
anims.push(
|
|
447
552
|
el.animate(
|
|
448
|
-
[{ transform:
|
|
553
|
+
[{ transform: txFn(s) }, { transform: txFn({ ...s, x: toX, y: toY }) }],
|
|
449
554
|
baseOpts
|
|
450
555
|
)
|
|
451
556
|
);
|
|
@@ -454,29 +559,45 @@ function buildAction(ev, el, s, baseOpts, delayMs, durMs, ast, states, scene, as
|
|
|
454
559
|
break;
|
|
455
560
|
}
|
|
456
561
|
// ── enter ───────────────────────────────────────────────────────────────
|
|
562
|
+
// Slides the actor from the given screen edge into its current (s)
|
|
563
|
+
// position while also restoring opacity to 1. The opacity restore makes
|
|
564
|
+
// `enter` symmetric with `exit` so actors can re-enter after exiting
|
|
565
|
+
// without needing a separate fade_in.
|
|
457
566
|
case "enter": {
|
|
458
567
|
const from = String(ev.params.from ?? "left");
|
|
459
|
-
const fromState =
|
|
460
|
-
switch (from) {
|
|
461
|
-
case "left":
|
|
462
|
-
fromState.x = -ast.meta.width;
|
|
463
|
-
break;
|
|
464
|
-
case "right":
|
|
465
|
-
fromState.x = ast.meta.width * 2;
|
|
466
|
-
break;
|
|
467
|
-
case "top":
|
|
468
|
-
fromState.y = -ast.meta.height;
|
|
469
|
-
break;
|
|
470
|
-
case "bottom":
|
|
471
|
-
fromState.y = ast.meta.height * 2;
|
|
472
|
-
break;
|
|
473
|
-
}
|
|
568
|
+
const fromState = offscreenState(s, from, ast.meta.width, ast.meta.height);
|
|
474
569
|
anims.push(
|
|
475
570
|
el.animate(
|
|
476
|
-
[
|
|
571
|
+
[
|
|
572
|
+
{ transform: txFn(fromState), opacity: s.opacity },
|
|
573
|
+
{ transform: txFn(s), opacity: 1 }
|
|
574
|
+
],
|
|
575
|
+
baseOpts
|
|
576
|
+
)
|
|
577
|
+
);
|
|
578
|
+
s.opacity = 1;
|
|
579
|
+
break;
|
|
580
|
+
}
|
|
581
|
+
// ── exit ────────────────────────────────────────────────────────────────
|
|
582
|
+
// Mirror of enter: slides off-screen in the given direction while also
|
|
583
|
+
// fading opacity to 0. Universal — works on any actor type (caption, text,
|
|
584
|
+
// figure, box, sprite). Leaves `s` at the off-screen state since the
|
|
585
|
+
// actor is conceptually gone after this.
|
|
586
|
+
case "exit": {
|
|
587
|
+
const to = String(ev.params.to ?? "right");
|
|
588
|
+
const toState = offscreenState(s, to, ast.meta.width, ast.meta.height);
|
|
589
|
+
anims.push(
|
|
590
|
+
el.animate(
|
|
591
|
+
[
|
|
592
|
+
{ transform: txFn(s), opacity: s.opacity },
|
|
593
|
+
{ transform: txFn(toState), opacity: 0 }
|
|
594
|
+
],
|
|
477
595
|
baseOpts
|
|
478
596
|
)
|
|
479
597
|
);
|
|
598
|
+
s.x = toState.x;
|
|
599
|
+
s.y = toState.y;
|
|
600
|
+
s.opacity = 0;
|
|
480
601
|
break;
|
|
481
602
|
}
|
|
482
603
|
// ── fade_in ─────────────────────────────────────────────────────────────
|
|
@@ -498,7 +619,7 @@ function buildAction(ev, el, s, baseOpts, delayMs, durMs, ast, states, scene, as
|
|
|
498
619
|
const toScale = typeof ev.params.to === "number" ? ev.params.to : s.scale;
|
|
499
620
|
anims.push(
|
|
500
621
|
el.animate(
|
|
501
|
-
[{ transform:
|
|
622
|
+
[{ transform: txFn(s) }, { transform: txFn({ ...s, scale: toScale }) }],
|
|
502
623
|
baseOpts
|
|
503
624
|
)
|
|
504
625
|
);
|
|
@@ -510,7 +631,7 @@ function buildAction(ev, el, s, baseOpts, delayMs, durMs, ast, states, scene, as
|
|
|
510
631
|
const toDeg = typeof ev.params.to === "number" ? ev.params.to : s.rotate;
|
|
511
632
|
anims.push(
|
|
512
633
|
el.animate(
|
|
513
|
-
[{ transform:
|
|
634
|
+
[{ transform: txFn(s) }, { transform: txFn({ ...s, rotate: toDeg }) }],
|
|
514
635
|
baseOpts
|
|
515
636
|
)
|
|
516
637
|
);
|
|
@@ -523,12 +644,12 @@ function buildAction(ev, el, s, baseOpts, delayMs, durMs, ast, states, scene, as
|
|
|
523
644
|
anims.push(
|
|
524
645
|
el.animate(
|
|
525
646
|
[
|
|
526
|
-
{ transform:
|
|
527
|
-
{ transform:
|
|
528
|
-
{ transform:
|
|
529
|
-
{ transform:
|
|
530
|
-
{ transform:
|
|
531
|
-
{ transform:
|
|
647
|
+
{ transform: txFn(s), offset: 0 },
|
|
648
|
+
{ transform: txFn({ ...s, x: s.x + mag }), offset: 0.2 },
|
|
649
|
+
{ transform: txFn({ ...s, x: s.x - mag }), offset: 0.4 },
|
|
650
|
+
{ transform: txFn({ ...s, x: s.x + mag }), offset: 0.6 },
|
|
651
|
+
{ transform: txFn({ ...s, x: s.x - mag }), offset: 0.8 },
|
|
652
|
+
{ transform: txFn(s), offset: 1 }
|
|
532
653
|
],
|
|
533
654
|
{ ...baseOpts, easing: "linear" }
|
|
534
655
|
)
|
|
@@ -739,12 +860,12 @@ function buildAction(ev, el, s, baseOpts, delayMs, durMs, ast, states, scene, as
|
|
|
739
860
|
anims.push(
|
|
740
861
|
el.animate(
|
|
741
862
|
[
|
|
742
|
-
{ transform:
|
|
743
|
-
{ transform:
|
|
744
|
-
{ transform:
|
|
745
|
-
{ transform:
|
|
746
|
-
{ transform:
|
|
747
|
-
{ transform:
|
|
863
|
+
{ transform: txFn(s), offset: 0 },
|
|
864
|
+
{ transform: txFn({ ...s, scale: s.scale * 0.9 }), offset: 0.1 },
|
|
865
|
+
{ transform: txFn({ ...s, y: s.y - jHeight, scale: s.scale * 1.1 }), offset: 0.45 },
|
|
866
|
+
{ transform: txFn({ ...s, y: s.y - jHeight * 0.3, scale: s.scale * 1.05 }), offset: 0.7 },
|
|
867
|
+
{ transform: txFn({ ...s, scale: s.scale * 0.92 }), offset: 0.88 },
|
|
868
|
+
{ transform: txFn(s), offset: 1 }
|
|
748
869
|
],
|
|
749
870
|
{ ...baseOpts, easing: "ease-in-out" }
|
|
750
871
|
)
|
|
@@ -779,24 +900,24 @@ function buildAction(ev, el, s, baseOpts, delayMs, durMs, ast, states, scene, as
|
|
|
779
900
|
case "bounce": {
|
|
780
901
|
const bIntensity = typeof ev.params.intensity === "number" ? ev.params.intensity : 15;
|
|
781
902
|
const bCount = typeof ev.params.count === "number" ? ev.params.count : 3;
|
|
782
|
-
const keyframes = [{ transform:
|
|
903
|
+
const keyframes = [{ transform: txFn(s), offset: 0 }];
|
|
783
904
|
for (let bi = 0; bi < bCount; bi++) {
|
|
784
905
|
const amp = bIntensity * Math.pow(0.55, bi);
|
|
785
906
|
const baseOffset = (bi + 0.5) / (bCount + 0.5);
|
|
786
907
|
const peakOffset = Math.min(baseOffset, 0.98);
|
|
787
908
|
const valleyOffset = Math.min(baseOffset + 0.25 / (bCount + 0.5), 0.99);
|
|
788
909
|
keyframes.push({
|
|
789
|
-
transform:
|
|
910
|
+
transform: txFn({ ...s, y: s.y - amp }),
|
|
790
911
|
offset: peakOffset
|
|
791
912
|
});
|
|
792
913
|
if (bi < bCount - 1) {
|
|
793
914
|
keyframes.push({
|
|
794
|
-
transform:
|
|
915
|
+
transform: txFn(s),
|
|
795
916
|
offset: valleyOffset
|
|
796
917
|
});
|
|
797
918
|
}
|
|
798
919
|
}
|
|
799
|
-
keyframes.push({ transform:
|
|
920
|
+
keyframes.push({ transform: txFn(s), offset: 1 });
|
|
800
921
|
anims.push(
|
|
801
922
|
el.animate(keyframes, { ...baseOpts, easing: "ease-out" })
|
|
802
923
|
);
|
|
@@ -872,9 +993,20 @@ function bgToTextColor(bg) {
|
|
|
872
993
|
return named[bg.toLowerCase()] ?? "#1a1a1a";
|
|
873
994
|
}
|
|
874
995
|
function createPlayer(opts) {
|
|
875
|
-
const {
|
|
876
|
-
|
|
996
|
+
const {
|
|
997
|
+
container,
|
|
998
|
+
code,
|
|
999
|
+
assets: assetOverrides = {},
|
|
1000
|
+
imports,
|
|
1001
|
+
autoplay = true,
|
|
1002
|
+
loop = true,
|
|
1003
|
+
copyright = true,
|
|
1004
|
+
progressBar = true,
|
|
1005
|
+
onWarning = (w) => console.warn(`[markdy] line ${w.line}: ${w.message} (${w.kind})`)
|
|
1006
|
+
} = opts;
|
|
1007
|
+
const ast = parse(code, imports ? { imports } : void 0);
|
|
877
1008
|
const totalDurationMs = (ast.meta.duration ?? 0) * 1e3;
|
|
1009
|
+
for (const w of ast.warnings) onWarning(w);
|
|
878
1010
|
const viewport = document.createElement("div");
|
|
879
1011
|
Object.assign(viewport.style, {
|
|
880
1012
|
position: "relative",
|
|
@@ -953,6 +1085,17 @@ function createPlayer(opts) {
|
|
|
953
1085
|
transformOrigin: "0 0"
|
|
954
1086
|
});
|
|
955
1087
|
viewport.appendChild(scene);
|
|
1088
|
+
const sceneContent = document.createElement("div");
|
|
1089
|
+
Object.assign(sceneContent.style, {
|
|
1090
|
+
position: "absolute",
|
|
1091
|
+
top: "0",
|
|
1092
|
+
left: "0",
|
|
1093
|
+
width: "100%",
|
|
1094
|
+
height: "100%",
|
|
1095
|
+
transformOrigin: "50% 50%",
|
|
1096
|
+
willChange: "transform"
|
|
1097
|
+
});
|
|
1098
|
+
scene.appendChild(sceneContent);
|
|
956
1099
|
function scaleScene() {
|
|
957
1100
|
const s = viewport.clientWidth / ast.meta.width;
|
|
958
1101
|
scene.style.transform = `scale(${s})`;
|
|
@@ -963,11 +1106,11 @@ function createPlayer(opts) {
|
|
|
963
1106
|
const actorEls = /* @__PURE__ */ new Map();
|
|
964
1107
|
for (const [name, def] of Object.entries(ast.actors)) {
|
|
965
1108
|
const el = createActorEl(name, def, ast.assets, assetOverrides);
|
|
966
|
-
|
|
1109
|
+
sceneContent.appendChild(el);
|
|
967
1110
|
actorEls.set(name, el);
|
|
968
1111
|
}
|
|
969
1112
|
const faceSwaps = [];
|
|
970
|
-
const allAnims = buildAnimations(ast, actorEls,
|
|
1113
|
+
const allAnims = buildAnimations(ast, actorEls, sceneContent, assetOverrides, faceSwaps);
|
|
971
1114
|
faceSwaps.sort((a, b) => a.timeMs - b.timeMs);
|
|
972
1115
|
for (const anim of allAnims) {
|
|
973
1116
|
anim.pause();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@markdy/renderer-dom",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.1",
|
|
4
4
|
"description": "Web Animations API renderer for MarkdyScript scenes.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -43,15 +43,18 @@
|
|
|
43
43
|
"access": "public"
|
|
44
44
|
},
|
|
45
45
|
"dependencies": {
|
|
46
|
-
"@markdy/core": "0.
|
|
46
|
+
"@markdy/core": "0.7.1"
|
|
47
47
|
},
|
|
48
48
|
"devDependencies": {
|
|
49
|
+
"jsdom": "^26.0.0",
|
|
49
50
|
"tsup": "^8.5.1",
|
|
50
|
-
"typescript": "^5.9.3"
|
|
51
|
+
"typescript": "^5.9.3",
|
|
52
|
+
"vitest": "^4.1.4"
|
|
51
53
|
},
|
|
52
54
|
"scripts": {
|
|
53
55
|
"build": "tsup",
|
|
54
56
|
"typecheck": "tsc --noEmit",
|
|
55
|
-
"lint": "tsc --noEmit"
|
|
57
|
+
"lint": "tsc --noEmit",
|
|
58
|
+
"test": "vitest run"
|
|
56
59
|
}
|
|
57
60
|
}
|