domotion-svg 0.13.1 → 0.13.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/animation/animator.js +33 -4
- package/package.json +1 -1
|
@@ -444,6 +444,14 @@ function renderTypingOverlay(overlay, frameIdx, frameStart, frameEnd, totalDurat
|
|
|
444
444
|
const speed = overlay.speed ?? 60;
|
|
445
445
|
const fontSize = overlay.fontSize ?? 14;
|
|
446
446
|
const charWidth = fontSize * 0.6; // monospace cell (overlay font is monospace)
|
|
447
|
+
// DM-1205: the typewriter reveal hides not-yet-typed text with a width-0 clip
|
|
448
|
+
// rect. Chrome renders a zero-area clip path as "clip everything" (text
|
|
449
|
+
// hidden, correct), but WebKit/Safari treats an EMPTY clip as "no clip" and
|
|
450
|
+
// paints the element in full — so on multi-line overlays every line past the
|
|
451
|
+
// first showed its whole text immediately (the shared text opacity is already
|
|
452
|
+
// 1 while the line waits its turn). Hiding with a tiny non-zero width keeps
|
|
453
|
+
// the clip non-empty so WebKit clips it too; 0.01px reveals no visible pixel.
|
|
454
|
+
const hiddenW = "0.01px";
|
|
447
455
|
const lineHeight = Math.round(fontSize * 1.35);
|
|
448
456
|
const color = overlay.color ?? "#e6edf3";
|
|
449
457
|
const typeStartMs = frameStart + delay;
|
|
@@ -512,7 +520,7 @@ function renderTypingOverlay(overlay, frameIdx, frameStart, frameEnd, totalDurat
|
|
|
512
520
|
const lineEndPct = pct(lineEndMs, totalDuration);
|
|
513
521
|
lineTimings.push({ li, startMs: lineStartMs, endMs: lineEndMs, len: line.length });
|
|
514
522
|
cumChars += line.length;
|
|
515
|
-
parts.push(` <defs><clipPath id="${clipId}"><rect class="${id}-rev${li}" x="${overlay.x}" y="${lineY - fontSize}" width="
|
|
523
|
+
parts.push(` <defs><clipPath id="${clipId}"><rect class="${id}-rev${li}" x="${overlay.x}" y="${lineY - fontSize}" width="${hiddenW}" height="${textHeight}" /></clipPath></defs>`);
|
|
516
524
|
parts.push(` <text class="${id}-text" x="${overlay.x}" y="${lineY}" fill="${color}" font-size="${fontSize}" font-family="'SF Mono', Menlo, Monaco, monospace" clip-path="url(#${clipId})">${escapeHtml(line)}</text>`);
|
|
517
525
|
// DM-1204: the reveal clip MUST sweep linearly so its right edge tracks the
|
|
518
526
|
// caret (whose position track is `linear`). Without an explicit timing
|
|
@@ -520,8 +528,10 @@ function renderTypingOverlay(overlay, frameIdx, frameStart, frameEnd, totalDurat
|
|
|
520
528
|
// through the sweep at the time-midpoint while the linear caret is only at
|
|
521
529
|
// 50% — that desync read as the caret lagging ~10–20 chars behind the
|
|
522
530
|
// revealed text mid-type, even though the endpoints (parked state) matched.
|
|
531
|
+
// DM-1205: the hidden state uses `hiddenW` (a tiny non-zero width), not 0,
|
|
532
|
+
// so WebKit's empty-clip-path fallback doesn't paint the whole line.
|
|
523
533
|
cssRules.push(`
|
|
524
|
-
@keyframes ${id}-rev${li} { 0%, ${lineStartPct} { width:
|
|
534
|
+
@keyframes ${id}-rev${li} { 0%, ${lineStartPct} { width: ${hiddenW}; } ${lineEndPct} { width: ${lineWidth}px; } ${holdEndPct} { width: ${lineWidth}px; } ${disappearPct}, 100% { width: ${hiddenW}; } }
|
|
525
535
|
.${id}-rev${li} { animation: ${id}-rev${li} ${totalSec.toFixed(2)}s linear infinite; }`);
|
|
526
536
|
});
|
|
527
537
|
// Whole-overlay visibility — shared by every line's <text>.
|
|
@@ -544,10 +554,26 @@ function renderTypingOverlay(overlay, frameIdx, frameStart, frameEnd, totalDurat
|
|
|
544
554
|
const endY = last.li * lineHeight;
|
|
545
555
|
// Position track: hold at line 0 start until typing begins, then sweep each
|
|
546
556
|
// line, then hold at the text end through the blink + disappear.
|
|
557
|
+
//
|
|
558
|
+
// DM-1204 (multi-line): a line ends and the next begins at the same instant
|
|
559
|
+
// (type timing is contiguous — line N+1 starts the ms line N finishes). The
|
|
560
|
+
// end-of-line stop (x = line width, row N) and the next line's left-margin
|
|
561
|
+
// stop (x = 0, row N+1) would therefore round to the SAME keyframe percent;
|
|
562
|
+
// CSS keeps the later declaration, dropping the end-of-line x so the caret
|
|
563
|
+
// stays pinned at x=0 and merely slides down each row. We keep percentages
|
|
564
|
+
// strictly increasing (nudging the carriage-return stop a hair past the
|
|
565
|
+
// line-end stop) so both survive — the jump back to the margin then happens
|
|
566
|
+
// over ~0.01% of the timeline, i.e. visually instant.
|
|
547
567
|
const posStops = [`0%, ${typeStartPct} { transform: translate(0px, 0px); }`];
|
|
568
|
+
let lastPctNum = pctNum(typeStartMs, totalDuration);
|
|
569
|
+
const pushPosStop = (pn, x, y) => {
|
|
570
|
+
const p = Math.max(pn, lastPctNum + 0.01);
|
|
571
|
+
posStops.push(`${p.toFixed(2)}% { transform: translate(${x}px, ${y}px); }`);
|
|
572
|
+
lastPctNum = p;
|
|
573
|
+
};
|
|
548
574
|
for (const lt of lineTimings) {
|
|
549
|
-
|
|
550
|
-
|
|
575
|
+
pushPosStop(pctNum(lt.startMs, totalDuration), 0, lt.li * lineHeight);
|
|
576
|
+
pushPosStop(pctNum(lt.endMs, totalDuration), lt.len * charWidth, lt.li * lineHeight);
|
|
551
577
|
}
|
|
552
578
|
posStops.push(`${holdEndPct}, 100% { transform: translate(${endX}px, ${endY}px); }`);
|
|
553
579
|
// Blink: invisible until typing starts, solid through typing, then toggle
|
|
@@ -618,6 +644,9 @@ function renderBlinkOverlay(overlay, frameIdx, frameStart, frameEnd, totalDurati
|
|
|
618
644
|
function pct(ms, total) {
|
|
619
645
|
return `${((ms / total) * 100).toFixed(2)}%`;
|
|
620
646
|
}
|
|
647
|
+
function pctNum(ms, total) {
|
|
648
|
+
return (ms / total) * 100;
|
|
649
|
+
}
|
|
621
650
|
/**
|
|
622
651
|
* DM-599: build a step-end keyframes block that toggles `display` between
|
|
623
652
|
* `none` and `inline` around a visible window. Used in parallel with the
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "domotion-svg",
|
|
3
|
-
"version": "0.13.
|
|
3
|
+
"version": "0.13.3",
|
|
4
4
|
"description": "DOM-to-animated-SVG renderer. Captures HTML/CSS via Playwright Chromium and converts it to self-contained SVG with CSS animations — pixel-faithful demos that scale crisply and load lazily.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Brian Westphal",
|