domotion-svg 0.15.0 → 0.17.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.
Files changed (116) hide show
  1. package/README.md +69 -8
  2. package/dist/animation/animator.d.ts +9 -0
  3. package/dist/animation/animator.js +276 -157
  4. package/dist/animation/composite.d.ts +133 -0
  5. package/dist/animation/composite.js +243 -0
  6. package/dist/animation/embed-timeline.d.ts +76 -0
  7. package/dist/animation/embed-timeline.js +212 -0
  8. package/dist/animation/index.d.ts +3 -0
  9. package/dist/animation/index.js +7 -0
  10. package/dist/animation/overlay-schema.d.ts +1 -1
  11. package/dist/animation/resolve-overlays.d.ts +3 -3
  12. package/dist/animation/resolve-overlays.js +2 -2
  13. package/dist/animation/svg-meta.d.ts +31 -0
  14. package/dist/animation/svg-meta.js +49 -0
  15. package/dist/capture/clip-rect.d.ts +29 -0
  16. package/dist/capture/clip-rect.js +23 -0
  17. package/dist/capture/embed.d.ts +13 -0
  18. package/dist/capture/embed.js +25 -6
  19. package/dist/capture/emoji.d.ts +8 -9
  20. package/dist/capture/emoji.js +115 -109
  21. package/dist/capture/index.d.ts +23 -11
  22. package/dist/capture/index.js +149 -154
  23. package/dist/capture/initial-letter-probe.js +10 -20
  24. package/dist/capture/script/index.js +48 -164
  25. package/dist/capture/script/utils.d.ts +1 -0
  26. package/dist/capture/script/utils.js +19 -0
  27. package/dist/capture/script/walker/borders-backgrounds.d.ts +130 -17
  28. package/dist/capture/script/walker/borders-backgrounds.js +236 -15
  29. package/dist/capture/script/walker/fieldset-legend.d.ts +12 -0
  30. package/dist/capture/script/walker/fieldset-legend.js +37 -0
  31. package/dist/capture/script/walker/fragmentation.d.ts +1 -0
  32. package/dist/capture/script/walker/fragmentation.js +114 -0
  33. package/dist/capture/script/walker/input-value.js +19 -9
  34. package/dist/capture/script/walker/lists-counters.d.ts +2 -0
  35. package/dist/capture/script/walker/lists-counters.js +21 -0
  36. package/dist/capture/script/walker/pseudo-content.d.ts +3 -2
  37. package/dist/capture/script/walker/pseudo-content.js +83 -14
  38. package/dist/capture/script/walker/pseudo-inject.js +11 -0
  39. package/dist/capture/script/walker/text-segments.js +9 -10
  40. package/dist/capture/script/walker/transforms.d.ts +1 -0
  41. package/dist/capture/script/walker/transforms.js +1 -1
  42. package/dist/capture/script.generated.js +1 -1
  43. package/dist/capture/types.d.ts +551 -520
  44. package/dist/cli/animate.d.ts +156 -16
  45. package/dist/cli/animate.js +322 -221
  46. package/dist/cli/capture.js +2 -1
  47. package/dist/cli/common.d.ts +37 -1
  48. package/dist/cli/common.js +85 -8
  49. package/dist/cli/composite-config-json-schema.d.ts +33 -0
  50. package/dist/cli/composite-config-json-schema.js +67 -0
  51. package/dist/cli/composite.d.ts +83 -0
  52. package/dist/cli/composite.js +222 -0
  53. package/dist/cli/index.js +8 -0
  54. package/dist/cli/review.js +15 -12
  55. package/dist/cli/scrubber.d.ts +3 -3
  56. package/dist/cli/scrubber.js +12 -12
  57. package/dist/cli/svg-to-image-core.d.ts +60 -0
  58. package/dist/cli/svg-to-image-core.js +159 -0
  59. package/dist/cli/svg-to-image.d.ts +14 -0
  60. package/dist/cli/svg-to-image.js +128 -0
  61. package/dist/cli/svg-to-video-core.d.ts +2 -8
  62. package/dist/cli/svg-to-video-core.js +9 -29
  63. package/dist/cli/svg-to-video.js +9 -24
  64. package/dist/cli/term.js +21 -4
  65. package/dist/render/borders.js +35 -51
  66. package/dist/render/conic-raster.js +11 -19
  67. package/dist/render/element-tree-to-svg.js +3277 -2924
  68. package/dist/render/embedded-font-builder.js +1 -0
  69. package/dist/render/font-resolution.d.ts +58 -4
  70. package/dist/render/font-resolution.js +416 -112
  71. package/dist/render/form-controls.js +10 -6
  72. package/dist/render/glyph-helper.js +14 -1
  73. package/dist/render/gradients.js +1 -18
  74. package/dist/render/helper-acquire.js +4 -1
  75. package/dist/render/index.d.ts +1 -1
  76. package/dist/render/index.js +1 -1
  77. package/dist/render/text-to-path.js +21 -21
  78. package/dist/render/text.js +40 -34
  79. package/dist/render/transforms.js +6 -3
  80. package/dist/render/unicode-font-routing.noto-linux.generated.d.ts +8 -0
  81. package/dist/render/unicode-font-routing.noto-linux.generated.js +487 -0
  82. package/dist/review/server.js +44 -44
  83. package/dist/scroll/composer.js +217 -218
  84. package/dist/scrubber/client.js +1 -1
  85. package/dist/scrubber/server.d.ts +1 -1
  86. package/dist/scrubber/server.js +13 -22
  87. package/dist/templates/builtin/background-loop.d.ts +1 -2
  88. package/dist/templates/builtin/background-loop.js +41 -48
  89. package/dist/templates/builtin/chart.d.ts +4 -3
  90. package/dist/templates/builtin/chart.js +146 -132
  91. package/dist/templates/builtin/chat.d.ts +1 -3
  92. package/dist/templates/builtin/chat.js +6 -14
  93. package/dist/templates/builtin/device-mockup.d.ts +3 -1
  94. package/dist/templates/builtin/device-mockup.js +32 -6
  95. package/dist/templates/builtin/kinetic-text.d.ts +1 -1
  96. package/dist/templates/builtin/kinetic-text.js +8 -16
  97. package/dist/templates/builtin/lower-third.js +9 -17
  98. package/dist/templates/builtin/subscribe.d.ts +1 -3
  99. package/dist/templates/builtin/subscribe.js +6 -14
  100. package/dist/templates/render.js +2 -1
  101. package/dist/templates/run-single-frame.d.ts +18 -0
  102. package/dist/templates/run-single-frame.js +27 -0
  103. package/dist/terminal/cast.js +1 -1
  104. package/dist/terminal/incremental.js +19 -21
  105. package/dist/terminal/index.js +7 -19
  106. package/dist/terminal/render.d.ts +17 -0
  107. package/dist/terminal/render.js +25 -0
  108. package/dist/terminal/theme.d.ts +14 -0
  109. package/dist/terminal/theme.js +22 -0
  110. package/dist/tree-ops/for-each-element.d.ts +12 -0
  111. package/dist/tree-ops/for-each-element.js +17 -0
  112. package/dist/utils/local-server.d.ts +24 -0
  113. package/dist/utils/local-server.js +30 -0
  114. package/llms.txt +157 -10
  115. package/package.json +10 -8
  116. package/schemas/composite-config.schema.json +200 -0
package/README.md CHANGED
@@ -2,7 +2,25 @@
2
2
  <img src="examples/output/domotion-word-demo.svg" alt="Domotion — an animated wordmark cycling through twenty neon-retro typographic variants of the word domotion" width="600">
3
3
  </p>
4
4
 
5
- DOM-to-animated-SVG renderer. Captures HTML/CSS rendered in headless Chromium and converts the captured tree into a self-contained SVG with optional CSS animations — pixel-faithful to what Chromium painted, scales crisply at any size, and embeds without external assets.
5
+ <p align="center">
6
+ <strong><a href="https://brianwestphal.github.io/domotion/">🌐 Website &amp; docs</a></strong>
7
+ &nbsp;·&nbsp;
8
+ <a href="https://brianwestphal.github.io/domotion/showcase/">Showcase</a>
9
+ &nbsp;·&nbsp;
10
+ <a href="https://brianwestphal.github.io/domotion/start/quickstart/">Quick start</a>
11
+ &nbsp;·&nbsp;
12
+ <a href="https://github.com/brianwestphal/domotion">GitHub</a>
13
+ </p>
14
+
15
+ **Domotion turns real HTML/CSS into one self-contained, animated SVG** — an accurate reproduction of the rendered page, with optional animation and simulated interaction built in. Text is emitted as real glyph paths, so it looks identical across browsers; the output scales crisply at any size and embeds anywhere with a plain `<img>`, no external assets.
16
+
17
+ Beyond raw capture it ships a **template library** that turns a few flags into a polished animated SVG, **terminal-session capture** (a recording → an animated terminal), **scroll capture** (a long page replayed as one self-contained scrolling SVG), multi-frame **animation** with transitions, overlays, and simulated interaction, **device-chrome** framing, **nested compositing** (animated layers inside animated layers), one-command **SVG → MP4/WebM**, and a fidelity **review** tool.
18
+
19
+ <p align="center">
20
+ <img src="examples/output/hero-product-demo.svg" alt="An analytics dashboard assembling itself inside a browser window — KPI cards rise in, a bar chart grows with its peak highlighted, a search query types itself, and a nav item is clicked — all in one self-contained animated SVG" width="760">
21
+ </p>
22
+
23
+ <p align="center"><sub>A real UI captured and brought to life — one self-contained SVG. <a href="https://brianwestphal.github.io/domotion/showcase/">More demos →</a></sub></p>
6
24
 
7
25
  ## Why
8
26
 
@@ -16,15 +34,13 @@ Domotion captures real HTML/CSS as it renders in Chromium, then emits a single i
16
34
 
17
35
  ## Status
18
36
 
19
- Earlyextracted in 2026-04 from the slicekit project where it had been incubating as `tools/svg-demo-gen`. APIs may still shift while the project's external surface stabilizes.
37
+ Actively developed, with a broad shipped surface capture, multi-frame animation (transitions, overlays, simulated interaction), the template library, terminal capture, nested compositing, and the video/image exports — exercised by an extensive visual-regression suite. The CLIs and the animate-config schema are stable in practice.
20
38
 
21
39
  ## Platform support
22
40
 
23
- Domotion ships as a normal npm package and is **designed** to work on macOS, Linux, and Windows the captured SVG is meant to be pixel-faithful to Chromium on whichever platform the capture is running on (CoreText fallback on macOS, fontconfig on Linux, DirectWrite on Windows).
41
+ Domotion runs on **macOS, Linux, and Windows**, and all three are calibrated. It renders text by extracting real system-font glyph outlines and matching how the browser falls back between fonts on the platform you run it on (CoreText on macOS, fontconfig on Linux, DirectWrite on Windows). macOS is held to pixel-exact parity; Linux and Windows match the browser's glyph selection and metrics within a small native-hinting margin (the residual is unhinted-outline-vs-native-raster rasterization, not missing calibration), and both are gated by visual-regression CI.
24
42
 
25
- **Today it's only actively tested and calibrated on macOS.** Linux and Windows are roadmap items: cross-platform system-font path discovery, per-platform fallback-font chains calibrated against the host Chromium, optional bundled fallback fonts when no local match resolves, and CI coverage on both platforms. The package will install and run on Linux/Windows, but text rendering won't yet match the host Chromium as faithfully as it does on macOS.
26
-
27
- If you'd like to help with cross-platform support — testing on Linux or Windows, reporting issues you hit, or sending fixes — please open an issue or PR on [GitHub](https://github.com/brianwestphal/domotion). Bug reports against macOS are also welcome.
43
+ Issues, fixes, and platform feedback are welcome on [GitHub](https://github.com/brianwestphal/domotion).
28
44
 
29
45
  ## Install
30
46
 
@@ -41,8 +57,10 @@ yourself to keep the first job's runtime down.
41
57
  The fastest way in is the `domotion` CLI — no TypeScript, no Playwright bring-up. Point it at a URL or HTML file:
42
58
 
43
59
  ```bash
44
- # Zero-install: run the published CLI straight from npm.
45
- npx domotion-svg capture https://example.com -o example.svg
60
+ # Zero-install: run the published CLI straight from npm. The package name is
61
+ # domotion-svg; -p installs it and `domotion` selects the bin (the package ships
62
+ # several bins, so the bin must be named explicitly).
63
+ npx -p domotion-svg domotion capture https://example.com -o example.svg
46
64
 
47
65
  # Capture a URL as SVG.
48
66
  domotion capture https://example.com -o example.svg
@@ -56,6 +74,9 @@ domotion capture ./demo.html \
56
74
 
57
75
  # Capture HTML piped on stdin.
58
76
  cat demo.html | domotion capture - -o demo.svg
77
+
78
+ # Capture a long page as one animated scrolling SVG (scrolls to the bottom over 8s).
79
+ domotion capture https://example.com --scroll "down:bottom/8s" -o scroll.svg
59
80
  ```
60
81
 
61
82
  For a multi-frame animated SVG, write a small JSON config and run `domotion animate`:
@@ -66,6 +87,31 @@ domotion animate ./demo.json
66
87
 
67
88
  The config describes each frame (input, duration, transition) plus a declarative surface for interaction demos: continuous-session frames that carry client-side state across steps (omit `input` / set `"continue": true`), DOM-mutation and interaction actions, richer readiness waits (`waitForText` / `waitForGone` / `waitForCount`), typing / tap / svg / blink overlays that can anchor to an element's box, an on-screen `cursor` (explicit or `"auto"`), `vars` + `${}` interpolation, and a small `evaluate` escape hatch. See `domotion --help` for the full grammar and the [Quick start](https://brianwestphal.github.io/domotion/start/quickstart/) for a walkthrough.
68
89
 
90
+ ### Templates — animated SVGs from a few flags
91
+
92
+ The fastest way to a polished result without writing any HTML. Each built-in is a parameterized generator; pass a few flags and get a self-contained animated SVG. `domotion template list` shows them, `domotion template <name> --help` shows a template's parameters.
93
+
94
+ ```bash
95
+ domotion template lower-third --title "Ada Lovelace" --subtitle "First Programmer" -o banner.svg
96
+ domotion template chart --type donut --data "42,28,18,12" --labels "Search,Direct,Social,Email" -o chart.svg
97
+ domotion template kinetic-text --text "Ship it" --variant pop --by char -o title.svg
98
+ ```
99
+
100
+ Built-ins: **lower-third** (broadcast banner) · **kinetic-text** (animated typography) · **chart** (column / bar / line / pie / donut) · **chat** (message thread) · **subscribe** (follow pop-up) · **background-loop** (seamless looping background) · **device-mockup** (wrap a page in a phone / browser / window bezel). Third-party templates are npm packages named `domotion-template-<name>`.
101
+
102
+ ### Terminal sessions
103
+
104
+ Turn a recorded terminal session into a self-contained animated SVG — real text, real color, native SVG (no raster frames). Record with [asciinema](https://asciinema.org), then convert:
105
+
106
+ ```bash
107
+ asciinema rec demo.cast -c "npm test"
108
+ domotion term --cast demo.cast -o demo.svg
109
+ ```
110
+
111
+ ### Compositing — animated layers inside animated layers
112
+
113
+ `domotion composite` stacks layers — a `cast`, a `template`, or a pre-rendered `svg`, any of which may be animated — into one SVG, each placed and on its own timeline with its animation preserved. This is how you nest one animated thing inside another, e.g. a terminal window resizing on a desktop. See `domotion composite --help` and `examples/composite/`.
114
+
69
115
  ### Export to video
70
116
 
71
117
  The package also ships a standalone `svg-to-video` CLI that renders an animated SVG (a `domotion animate` output, or any CSS-/SMIL-animated SVG) to a video file. It steps the animation timeline frame by frame in Chromium for frame-accurate timing, then pipes the frames to **ffmpeg** (a required external dependency — install via `brew` / `apt` / `winget`).
@@ -80,6 +126,19 @@ svg-to-video demo.svg -o demo.webm --format vp9 --fps 60 --music bed.mp3
80
126
 
81
127
  Supports target size (`--width`/`--height`, aspect-preserving), `--fps`, `--format` / `--container`, supersampling (`--scale`), background music / foreground audio / captions, and a disk-space pre-flight. See `svg-to-video --help`.
82
128
 
129
+ ### Export to a still image
130
+
131
+ To turn a single SVG into an image — to look at a render, embed a thumbnail, or hand off a flat asset — the package ships an `svg-to-image` CLI. The output format follows the `-o` extension: PNG / WebP / AVIF / TIFF (keep alpha for transparent SVGs), JPEG (`--quality`), or a single-page vector PDF. (WebP/AVIF/TIFF are transcoded with the bundled `sharp` — no extra install.)
132
+
133
+ ```bash
134
+ svg-to-image card.svg -o card.png # PNG at the SVG's intrinsic size
135
+ svg-to-image card.svg -o card@2x.png --scale 2 # crisp retina (2×) raster
136
+ svg-to-image demo.svg -o frame.png --at 4000 # one frame of an animated SVG, at 4s
137
+ svg-to-image poster.svg -o poster.pdf # vector PDF
138
+ ```
139
+
140
+ `--at <ms>` samples an animated SVG's timeline, `--width`/`--height` contain preserving aspect, `--scale` supersamples raster output. See `svg-to-image --help`.
141
+
83
142
  ### Reviewing a regression
84
143
 
85
144
  If a capture comes out looking different from how Chromium painted the source page, the package ships an `svg-review` CLI to help you file a focused bug report. Capture once with `--debug` to get a reproduction bundle (HAR + the Chromium screenshot of the source + the SVG we produced), then open the bundle in the local review UI:
@@ -91,6 +150,8 @@ svg-review --expected example.debug/expected.png --actual example.debug/actual.s
91
150
 
92
151
  The browser opens a single review card showing the expected / actual / diff PNGs. Arrow keys cycle through the three at full size; drag on any image to mark a problem region and caption it. The side panel builds a GitHub-issue-ready Markdown block as you go — copy it, then file the issue at <https://github.com/brianwestphal/domotion/issues/new> and attach `expected.png` + `actual.svg` so a maintainer can reproduce.
93
152
 
153
+ For an *animated* SVG, the package also ships `svg-scrubber` — a local video-style bench to play / pause / scrub / mark an in-out range, export the current frame as PNG, export the range as MP4, or trim it to a new self-contained animated SVG.
154
+
94
155
  ### Scripting API
95
156
 
96
157
  When you outgrow the CLI — custom interaction loops, programmatic frame composition, custom overlays — the same primitives are available as a library:
@@ -24,6 +24,15 @@ export interface AnimationFrame {
24
24
  cullCss?: string;
25
25
  /** Duration this frame is shown (ms) */
26
26
  duration: number;
27
+ /**
28
+ * DM-1319: this frame's `svgContent` is itself a self-contained *animated* SVG
29
+ * (a `cast` / `template` frame) whose internal timeline should start when the
30
+ * frame becomes visible, not at the master-loop origin. Set to the embedded
31
+ * content's own play length (ms); the animator re-anchors its keyframes into
32
+ * the `[frameStart, frameStart + period]` window of the master loop (see
33
+ * `offsetEmbeddedAnimatedSvgTimeline`). Omit for ordinary captured frames.
34
+ */
35
+ embeddedAnimationPeriodMs?: number;
27
36
  /** Transition to next frame */
28
37
  transition?: {
29
38
  /**