@markdy/renderer-dom 0.7.23 → 0.7.25
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/README.md +8 -0
- package/dist/index.d.ts +12 -1
- package/dist/index.js +46 -5
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -70,6 +70,9 @@ player.destroy(); // clean up DOM + cancel animations
|
|
|
70
70
|
| `loop` | `boolean` | `true` | Loop the animation when it reaches the end |
|
|
71
71
|
| `copyright` | `boolean` | `true` | Show a small "Powered by Markdy" badge below the animation |
|
|
72
72
|
| `progressBar` | `boolean` | `true` | Show a rainbow progress bar around the viewport border |
|
|
73
|
+
| `onWarning` | `(warning: ParseWarning) => void` | `console.warn` | Called for each soft parse warning |
|
|
74
|
+
| `onTimeUpdate` | `(seconds: number, durationSeconds: number) => void` | — | Called whenever playback or seek changes the current time |
|
|
75
|
+
| `onPlayStateChange` | `(playing: boolean) => void` | — | Called when playback starts or pauses |
|
|
73
76
|
|
|
74
77
|
### `Player`
|
|
75
78
|
|
|
@@ -78,6 +81,11 @@ player.destroy(); // clean up DOM + cancel animations
|
|
|
78
81
|
| `play()` | Start or resume playback |
|
|
79
82
|
| `pause()` | Pause at current position |
|
|
80
83
|
| `seek(seconds)` | Jump to a specific time |
|
|
84
|
+
| `currentTime()` | Current playback position in seconds |
|
|
85
|
+
| `duration()` | Total scene duration in seconds |
|
|
86
|
+
| `isPlaying()` | Whether the scene is currently playing |
|
|
87
|
+
| `chapters()` | Named `scene "..." { ... }` chapter blocks, in author order (empty if none) |
|
|
88
|
+
| `seekToChapter(name)` | Seek to the start of a named chapter; no-op if the name doesn't match |
|
|
81
89
|
| `destroy()` | Remove DOM elements and cancel all animations |
|
|
82
90
|
|
|
83
91
|
## Module Structure
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { SceneAST, ParseWarning } from '@markdy/core';
|
|
1
|
+
import { Chapter, SceneAST, ParseWarning } from '@markdy/core';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* @markdy/renderer-dom — Player
|
|
@@ -46,11 +46,22 @@ interface PlayerOptions {
|
|
|
46
46
|
* Pass a no-op to silence; pass a custom collector to surface warnings in a UI.
|
|
47
47
|
*/
|
|
48
48
|
onWarning?: (warning: ParseWarning) => void;
|
|
49
|
+
/** Invoked whenever playback or seek changes the current timeline time. */
|
|
50
|
+
onTimeUpdate?: (seconds: number, durationSeconds: number) => void;
|
|
51
|
+
/** Invoked when playback starts or pauses. */
|
|
52
|
+
onPlayStateChange?: (playing: boolean) => void;
|
|
49
53
|
}
|
|
50
54
|
interface Player {
|
|
51
55
|
play(): void;
|
|
52
56
|
pause(): void;
|
|
53
57
|
seek(seconds: number): void;
|
|
58
|
+
currentTime(): number;
|
|
59
|
+
duration(): number;
|
|
60
|
+
isPlaying(): boolean;
|
|
61
|
+
/** Named `scene "..." { ... }` chapter blocks, in author order. Empty when the scene has none. */
|
|
62
|
+
chapters(): Chapter[];
|
|
63
|
+
/** Seeks to the start of the named chapter. No-op if the name doesn't match a chapter. */
|
|
64
|
+
seekToChapter(name: string): void;
|
|
54
65
|
destroy(): void;
|
|
55
66
|
}
|
|
56
67
|
declare function createPlayer(opts: PlayerOptions): Player;
|
package/dist/index.js
CHANGED
|
@@ -21,10 +21,20 @@ var EASE_MAP = {
|
|
|
21
21
|
linear: "linear",
|
|
22
22
|
in: "ease-in",
|
|
23
23
|
out: "ease-out",
|
|
24
|
-
inout: "ease-in-out"
|
|
24
|
+
inout: "ease-in-out",
|
|
25
|
+
// Named cubic-bezier presets for authors who want a more polished feel
|
|
26
|
+
// than the four raw CSS keywords above without hand-writing a curve.
|
|
27
|
+
smooth: "cubic-bezier(0.4, 0, 0.2, 1)",
|
|
28
|
+
snappy: "cubic-bezier(0.16, 1, 0.3, 1)",
|
|
29
|
+
overshoot: "cubic-bezier(0.34, 1.56, 0.64, 1)",
|
|
30
|
+
sharp: "cubic-bezier(0.4, 0, 1, 1)"
|
|
25
31
|
};
|
|
32
|
+
var CUBIC_BEZIER_RE = /^cubic-bezier\(\s*-?\d*\.?\d+\s*,\s*-?\d*\.?\d+\s*,\s*-?\d*\.?\d+\s*,\s*-?\d*\.?\d+\s*\)$/;
|
|
26
33
|
function toEasing(val) {
|
|
27
|
-
|
|
34
|
+
const str = String(val ?? "");
|
|
35
|
+
if (EASE_MAP[str]) return EASE_MAP[str];
|
|
36
|
+
if (CUBIC_BEZIER_RE.test(str)) return str;
|
|
37
|
+
return "linear";
|
|
28
38
|
}
|
|
29
39
|
|
|
30
40
|
// src/figure.ts
|
|
@@ -450,6 +460,12 @@ function createActorEl(name, def, assetDefs, assetOverrides) {
|
|
|
450
460
|
}
|
|
451
461
|
|
|
452
462
|
// src/animations.ts
|
|
463
|
+
var DEFAULT_EASE_BY_ACTION = {
|
|
464
|
+
enter: "out",
|
|
465
|
+
fade_in: "out",
|
|
466
|
+
exit: "in",
|
|
467
|
+
fade_out: "in"
|
|
468
|
+
};
|
|
453
469
|
function isSceneDark(scene) {
|
|
454
470
|
const bg = scene.style.background || "white";
|
|
455
471
|
let hex = bg.trim().replace(/^#/, "");
|
|
@@ -483,7 +499,7 @@ function buildAnimations(ast, actorEls, scene, assetOverrides, faceSwaps) {
|
|
|
483
499
|
1,
|
|
484
500
|
(typeof ev.params.dur === "number" ? ev.params.dur : 0.5) * 1e3
|
|
485
501
|
);
|
|
486
|
-
const easing = toEasing(ev.params.ease);
|
|
502
|
+
const easing = toEasing(ev.params.ease ?? DEFAULT_EASE_BY_ACTION[ev.action]);
|
|
487
503
|
const baseOpts = {
|
|
488
504
|
delay: delayMs,
|
|
489
505
|
duration: durMs,
|
|
@@ -1328,10 +1344,13 @@ function createPlayer(opts) {
|
|
|
1328
1344
|
loop = true,
|
|
1329
1345
|
copyright = true,
|
|
1330
1346
|
progressBar = true,
|
|
1331
|
-
onWarning = (w) => console.warn(`[markdy] line ${w.line}: ${w.message} (${w.kind})`)
|
|
1347
|
+
onWarning = (w) => console.warn(`[markdy] line ${w.line}: ${w.message} (${w.kind})`),
|
|
1348
|
+
onTimeUpdate,
|
|
1349
|
+
onPlayStateChange
|
|
1332
1350
|
} = opts;
|
|
1333
1351
|
const ast = parse(code, imports ? { imports } : void 0);
|
|
1334
1352
|
const totalDurationMs = (ast.meta.duration ?? 0) * 1e3;
|
|
1353
|
+
const durationSeconds = totalDurationMs / 1e3;
|
|
1335
1354
|
for (const w of ast.warnings) onWarning(w);
|
|
1336
1355
|
const viewport = document.createElement("div");
|
|
1337
1356
|
Object.assign(viewport.style, {
|
|
@@ -1456,6 +1475,7 @@ function createPlayer(opts) {
|
|
|
1456
1475
|
anim.currentTime = sceneMs;
|
|
1457
1476
|
}
|
|
1458
1477
|
applyFaceSwaps();
|
|
1478
|
+
onTimeUpdate?.(sceneMs / 1e3, durationSeconds);
|
|
1459
1479
|
}
|
|
1460
1480
|
function applyFaceSwaps() {
|
|
1461
1481
|
if (faceSwaps.length === 0) return;
|
|
@@ -1489,6 +1509,7 @@ function createPlayer(opts) {
|
|
|
1489
1509
|
sceneMs = totalDurationMs;
|
|
1490
1510
|
applyCurrentTime();
|
|
1491
1511
|
isPlaying = false;
|
|
1512
|
+
onPlayStateChange?.(false);
|
|
1492
1513
|
lastRafTs = null;
|
|
1493
1514
|
rafId = null;
|
|
1494
1515
|
return;
|
|
@@ -1502,12 +1523,14 @@ function createPlayer(opts) {
|
|
|
1502
1523
|
play() {
|
|
1503
1524
|
if (isPlaying) return;
|
|
1504
1525
|
isPlaying = true;
|
|
1526
|
+
onPlayStateChange?.(true);
|
|
1505
1527
|
lastRafTs = null;
|
|
1506
1528
|
rafId = requestAnimationFrame(rafTick);
|
|
1507
1529
|
},
|
|
1508
1530
|
pause() {
|
|
1509
1531
|
if (!isPlaying) return;
|
|
1510
1532
|
isPlaying = false;
|
|
1533
|
+
onPlayStateChange?.(false);
|
|
1511
1534
|
if (rafId !== null) {
|
|
1512
1535
|
cancelAnimationFrame(rafId);
|
|
1513
1536
|
rafId = null;
|
|
@@ -1515,10 +1538,28 @@ function createPlayer(opts) {
|
|
|
1515
1538
|
lastRafTs = null;
|
|
1516
1539
|
},
|
|
1517
1540
|
seek(seconds) {
|
|
1518
|
-
|
|
1541
|
+
const nextMs = seconds * 1e3;
|
|
1542
|
+
sceneMs = totalDurationMs > 0 ? Math.min(Math.max(nextMs, 0), totalDurationMs) : Math.max(nextMs, 0);
|
|
1519
1543
|
applyCurrentTime();
|
|
1520
1544
|
if (totalDurationMs > 0) updateProgressBar(sceneMs / totalDurationMs);
|
|
1521
1545
|
},
|
|
1546
|
+
currentTime() {
|
|
1547
|
+
return sceneMs / 1e3;
|
|
1548
|
+
},
|
|
1549
|
+
duration() {
|
|
1550
|
+
return durationSeconds;
|
|
1551
|
+
},
|
|
1552
|
+
isPlaying() {
|
|
1553
|
+
return isPlaying;
|
|
1554
|
+
},
|
|
1555
|
+
chapters() {
|
|
1556
|
+
return ast.chapters;
|
|
1557
|
+
},
|
|
1558
|
+
seekToChapter(name) {
|
|
1559
|
+
const chapter = ast.chapters.find((c) => c.name === name);
|
|
1560
|
+
if (!chapter) return;
|
|
1561
|
+
player.seek(chapter.startTime);
|
|
1562
|
+
},
|
|
1522
1563
|
destroy() {
|
|
1523
1564
|
player.pause();
|
|
1524
1565
|
for (const anim of allAnims) anim.cancel();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@markdy/renderer-dom",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.25",
|
|
4
4
|
"description": "Web Animations API renderer for MarkdyScript scenes.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
"access": "public"
|
|
44
44
|
},
|
|
45
45
|
"dependencies": {
|
|
46
|
-
"@markdy/core": "0.7.
|
|
46
|
+
"@markdy/core": "0.7.25"
|
|
47
47
|
},
|
|
48
48
|
"devDependencies": {
|
|
49
49
|
"jsdom": "^29.1.1",
|