domotion-svg 0.13.1 → 0.13.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.
@@ -544,10 +544,26 @@ function renderTypingOverlay(overlay, frameIdx, frameStart, frameEnd, totalDurat
544
544
  const endY = last.li * lineHeight;
545
545
  // Position track: hold at line 0 start until typing begins, then sweep each
546
546
  // line, then hold at the text end through the blink + disappear.
547
+ //
548
+ // DM-1204 (multi-line): a line ends and the next begins at the same instant
549
+ // (type timing is contiguous — line N+1 starts the ms line N finishes). The
550
+ // end-of-line stop (x = line width, row N) and the next line's left-margin
551
+ // stop (x = 0, row N+1) would therefore round to the SAME keyframe percent;
552
+ // CSS keeps the later declaration, dropping the end-of-line x so the caret
553
+ // stays pinned at x=0 and merely slides down each row. We keep percentages
554
+ // strictly increasing (nudging the carriage-return stop a hair past the
555
+ // line-end stop) so both survive — the jump back to the margin then happens
556
+ // over ~0.01% of the timeline, i.e. visually instant.
547
557
  const posStops = [`0%, ${typeStartPct} { transform: translate(0px, 0px); }`];
558
+ let lastPctNum = pctNum(typeStartMs, totalDuration);
559
+ const pushPosStop = (pn, x, y) => {
560
+ const p = Math.max(pn, lastPctNum + 0.01);
561
+ posStops.push(`${p.toFixed(2)}% { transform: translate(${x}px, ${y}px); }`);
562
+ lastPctNum = p;
563
+ };
548
564
  for (const lt of lineTimings) {
549
- posStops.push(`${pct(lt.startMs, totalDuration)} { transform: translate(0px, ${lt.li * lineHeight}px); }`);
550
- posStops.push(`${pct(lt.endMs, totalDuration)} { transform: translate(${lt.len * charWidth}px, ${lt.li * lineHeight}px); }`);
565
+ pushPosStop(pctNum(lt.startMs, totalDuration), 0, lt.li * lineHeight);
566
+ pushPosStop(pctNum(lt.endMs, totalDuration), lt.len * charWidth, lt.li * lineHeight);
551
567
  }
552
568
  posStops.push(`${holdEndPct}, 100% { transform: translate(${endX}px, ${endY}px); }`);
553
569
  // Blink: invisible until typing starts, solid through typing, then toggle
@@ -618,6 +634,9 @@ function renderBlinkOverlay(overlay, frameIdx, frameStart, frameEnd, totalDurati
618
634
  function pct(ms, total) {
619
635
  return `${((ms / total) * 100).toFixed(2)}%`;
620
636
  }
637
+ function pctNum(ms, total) {
638
+ return (ms / total) * 100;
639
+ }
621
640
  /**
622
641
  * DM-599: build a step-end keyframes block that toggles `display` between
623
642
  * `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.1",
3
+ "version": "0.13.2",
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",