silvery 0.21.0 → 0.23.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 (224) hide show
  1. package/README.md +1 -1
  2. package/dist/{Text-Lq0dmj8-.mjs → Text-Ci6UCSTL.mjs} +46 -48
  3. package/dist/Text-Ci6UCSTL.mjs.map +1 -0
  4. package/dist/{render-string-DkQacASz.mjs → ag-q9lRlKlt.mjs} +5322 -4259
  5. package/dist/ag-q9lRlKlt.mjs.map +1 -0
  6. package/dist/{animation-ZMN2_XKv.mjs → animation-CZ4x2R7C.mjs} +1 -1
  7. package/dist/{animation-ZMN2_XKv.mjs.map → animation-CZ4x2R7C.mjs.map} +1 -1
  8. package/dist/{ansi-D1KQMAbf.mjs → ansi-CLmIMnop.mjs} +1 -1
  9. package/dist/{ansi-D1KQMAbf.mjs.map → ansi-CLmIMnop.mjs.map} +1 -1
  10. package/dist/{ansi-2Xn0yatP.d.mts → ansi-zmNzgkPB.d.mts} +1 -1
  11. package/dist/{ansi-2Xn0yatP.d.mts.map → ansi-zmNzgkPB.d.mts.map} +1 -1
  12. package/dist/{backend-B-WYLUib.mjs → backend-DSiSIc-h.mjs} +2 -2
  13. package/dist/{backend-B-WYLUib.mjs.map → backend-DSiSIc-h.mjs.map} +1 -1
  14. package/dist/chain-bridge-CkYcMxlq.mjs +4149 -0
  15. package/dist/chain-bridge-CkYcMxlq.mjs.map +1 -0
  16. package/dist/{chunk-BSw8zbkd.mjs → chunk-BEJ448es.mjs} +1 -3
  17. package/dist/cli-VNqUKlXw.mjs +4 -0
  18. package/dist/{context-BU5LkkIy.mjs → context-CEhuD1R_.mjs} +1 -1
  19. package/dist/{context-BU5LkkIy.mjs.map → context-CEhuD1R_.mjs.map} +1 -1
  20. package/dist/devtools-BF4IMumr.mjs +2 -0
  21. package/dist/{devtools-DcQjgyjL.mjs → devtools-td2AjFwc.mjs} +5 -5
  22. package/dist/{devtools-DcQjgyjL.mjs.map → devtools-td2AjFwc.mjs.map} +1 -1
  23. package/dist/{easing-BI-ASGMO.d.mts → easing-C5MrdO7V.d.mts} +1 -1
  24. package/dist/{easing-BI-ASGMO.d.mts.map → easing-C5MrdO7V.d.mts.map} +1 -1
  25. package/dist/{eta-CJlGH06n.mjs → eta-BwYWEjfS.mjs} +1 -1
  26. package/dist/{eta-CJlGH06n.mjs.map → eta-BwYWEjfS.mjs.map} +1 -1
  27. package/dist/{flexily-zero-adapter-C4lW_Ov5.mjs → flexily-zero-adapter-DktX3HsX.mjs} +1 -1
  28. package/dist/{flexily-zero-adapter-C3Vj0fPt.mjs → flexily-zero-adapter-VoBGHG14.mjs} +1 -1
  29. package/dist/{flexily-zero-adapter-C3Vj0fPt.mjs.map → flexily-zero-adapter-VoBGHG14.mjs.map} +1 -1
  30. package/dist/hit-registry-D_nxOivS.d.mts +71 -0
  31. package/dist/hit-registry-D_nxOivS.d.mts.map +1 -0
  32. package/dist/{UPNG-DosRPdF4.mjs → image-CIF75xMr.mjs} +891 -6
  33. package/dist/image-CIF75xMr.mjs.map +1 -0
  34. package/dist/{index-CSQf13CI.d.mts → index-377zdPLP.d.mts} +35 -12
  35. package/dist/index-377zdPLP.d.mts.map +1 -0
  36. package/dist/{index-Cl9KKjQ_.d.mts → index-BcSr0RAQ.d.mts} +8670 -10659
  37. package/dist/index-BcSr0RAQ.d.mts.map +1 -0
  38. package/dist/{index-XbNrPhWl.d.mts → index-DLnpxDAm.d.mts} +2 -2
  39. package/dist/{index-XbNrPhWl.d.mts.map → index-DLnpxDAm.d.mts.map} +1 -1
  40. package/dist/{index-BUMxS65f.d.mts → index-DlNmckTq.d.mts} +2 -2
  41. package/dist/{index-BUMxS65f.d.mts.map → index-DlNmckTq.d.mts.map} +1 -1
  42. package/dist/index.d.mts +12 -8
  43. package/dist/index.d.mts.map +1 -1
  44. package/dist/index.mjs +18 -15
  45. package/dist/index.mjs.map +1 -1
  46. package/dist/{layout-engine-C2px0RJE.mjs → layout-engine-BgR58vL0.mjs} +3 -3
  47. package/dist/{layout-engine-C2px0RJE.mjs.map → layout-engine-BgR58vL0.mjs.map} +1 -1
  48. package/dist/{layout-engine-C07LEXWT.mjs → layout-engine-DNjTha8f.mjs} +1 -1
  49. package/dist/{layout-signals-Cnw6xk8Q.mjs → layout-signals-CGYbHmxy.mjs} +146 -23
  50. package/dist/layout-signals-CGYbHmxy.mjs.map +1 -0
  51. package/dist/{bound-term-0sPrrzH1.d.mts → mouse-events-B2z5tbsL.d.mts} +780 -379
  52. package/dist/mouse-events-B2z5tbsL.d.mts.map +1 -0
  53. package/dist/{mouse-events-Dki3ISIp.mjs → mouse-events-WQ2h-uqG.mjs} +45 -10
  54. package/dist/mouse-events-WQ2h-uqG.mjs.map +1 -0
  55. package/dist/{multi-progress-DHZ2xUT2.d.mts → multi-progress-BaEFfHKP.d.mts} +2 -2
  56. package/dist/{multi-progress-DHZ2xUT2.d.mts.map → multi-progress-BaEFfHKP.d.mts.map} +1 -1
  57. package/dist/{multi-progress-CIRjrzma.mjs → multi-progress-zCWHEm9P.mjs} +3 -3
  58. package/dist/{multi-progress-CIRjrzma.mjs.map → multi-progress-zCWHEm9P.mjs.map} +1 -1
  59. package/dist/{node-CjM5Rt-M.mjs → node-CJ3J_rW-.mjs} +1 -1
  60. package/dist/{node-CjM5Rt-M.mjs.map → node-CJ3J_rW-.mjs.map} +1 -1
  61. package/dist/{progress-DB_Xo071.mjs → progress-6vJ7nxUg.mjs} +4 -4
  62. package/dist/{progress-DB_Xo071.mjs.map → progress-6vJ7nxUg.mjs.map} +1 -1
  63. package/dist/{progress-bar-oJwq22CR.mjs → progress-bar-BlFNsZL8.mjs} +4 -4
  64. package/dist/{progress-bar-oJwq22CR.mjs.map → progress-bar-BlFNsZL8.mjs.map} +1 -1
  65. package/dist/{reconciler-DldIJB93.mjs → reconciler--_-biN23.mjs} +190 -134
  66. package/dist/reconciler--_-biN23.mjs.map +1 -0
  67. package/dist/{render-string-BcoCpjCB.mjs → render-string-DaghHpLN.mjs} +1 -1
  68. package/dist/render-string-DtHZP0cU.mjs +215 -0
  69. package/dist/render-string-DtHZP0cU.mjs.map +1 -0
  70. package/dist/runtime.d.mts +4 -3
  71. package/dist/runtime.mjs +4 -3
  72. package/dist/schemes-DWQPxXAi.mjs +2516 -0
  73. package/dist/{schemes-JjNp4aSl.mjs.map → schemes-DWQPxXAi.mjs.map} +1 -1
  74. package/dist/{spinner-D9lrHr8s.mjs → spinner-B50hILqx.mjs} +19 -4
  75. package/dist/{spinner-D9lrHr8s.mjs.map → spinner-B50hILqx.mjs.map} +1 -1
  76. package/dist/{spinner-CZINHpkV.d.mts → spinner-DN10UfF0.d.mts} +2 -2
  77. package/dist/{spinner-CZINHpkV.d.mts.map → spinner-DN10UfF0.d.mts.map} +1 -1
  78. package/dist/{src-BNTToU7l.mjs → src-B8lf1kiR.mjs} +1507 -1166
  79. package/dist/src-B8lf1kiR.mjs.map +1 -0
  80. package/dist/{src-5w9QR6_8.mjs → src-BOLdi3WG.mjs} +105 -237
  81. package/dist/src-BOLdi3WG.mjs.map +1 -0
  82. package/dist/{src-BR4xNwdG.mjs → src-BXeTHHlL.mjs} +20240 -25437
  83. package/dist/src-BXeTHHlL.mjs.map +1 -0
  84. package/dist/{src-DKp-_OFG.mjs → src-BqeBFB3X.mjs} +90 -47
  85. package/dist/src-BqeBFB3X.mjs.map +1 -0
  86. package/dist/src-DbqcSrhy.mjs +3901 -0
  87. package/dist/src-DbqcSrhy.mjs.map +1 -0
  88. package/dist/{steps-Bp2uNqnn.d.mts → steps-B2kBmFpb.d.mts} +1 -1
  89. package/dist/{steps-Bp2uNqnn.d.mts.map → steps-B2kBmFpb.d.mts.map} +1 -1
  90. package/dist/{svg-Cz0UXcDj.mjs → svg-NmV9dgB9.mjs} +1 -1
  91. package/dist/{svg-Cz0UXcDj.mjs.map → svg-NmV9dgB9.mjs.map} +1 -1
  92. package/dist/{svg-g1D6ErwR.d.mts → svg-VUr78l5d.d.mts} +1 -1
  93. package/dist/{svg-g1D6ErwR.d.mts.map → svg-VUr78l5d.d.mts.map} +1 -1
  94. package/dist/term.d.mts +2 -2
  95. package/dist/term.mjs +3 -8
  96. package/dist/test.d.mts +673 -0
  97. package/dist/test.d.mts.map +1 -0
  98. package/dist/test.mjs +2829 -0
  99. package/dist/test.mjs.map +1 -0
  100. package/dist/theme.d.mts +2 -2
  101. package/dist/theme.d.mts.map +1 -1
  102. package/dist/theme.mjs +3 -8
  103. package/dist/{types-kt_fKR37.d.mts → types-D_E0FbqA.d.mts} +1 -1
  104. package/dist/{types-kt_fKR37.d.mts.map → types-D_E0FbqA.d.mts.map} +1 -1
  105. package/dist/ui/animation.d.mts +2 -2
  106. package/dist/ui/animation.mjs +1 -1
  107. package/dist/ui/ansi.d.mts +1 -1
  108. package/dist/ui/ansi.mjs +1 -1
  109. package/dist/ui/cli.d.mts +3 -3
  110. package/dist/ui/cli.mjs +5 -5
  111. package/dist/ui/image.d.mts +1 -1
  112. package/dist/ui/image.mjs +1 -1
  113. package/dist/ui/progress.d.mts +4 -4
  114. package/dist/ui/progress.mjs +4 -4
  115. package/dist/ui/react.d.mts +1 -1
  116. package/dist/ui/react.mjs +2 -2
  117. package/dist/ui/recording-chrome-react.d.mts +1 -1
  118. package/dist/ui/recording-chrome-react.mjs +2 -2
  119. package/dist/ui/recording-chrome.d.mts +1 -1
  120. package/dist/ui/recording-chrome.mjs +1 -1
  121. package/dist/ui/utils.mjs +1 -1
  122. package/dist/ui/wrappers.d.mts +2 -2
  123. package/dist/ui/wrappers.mjs +1 -1
  124. package/dist/ui.d.mts +6 -6
  125. package/dist/ui.mjs +7 -7
  126. package/dist/unicode-CxyxVGmB.mjs +11077 -0
  127. package/dist/unicode-CxyxVGmB.mjs.map +1 -0
  128. package/dist/{useLatest-DRDDVwjh.d.mts → useLatest-UOvWy0ZW.d.mts} +2 -2
  129. package/dist/{useLatest-DRDDVwjh.d.mts.map → useLatest-UOvWy0ZW.d.mts.map} +1 -1
  130. package/dist/useLayout-D5cE8OCI.mjs +424 -0
  131. package/dist/useLayout-D5cE8OCI.mjs.map +1 -0
  132. package/dist/{with-text-input-YeohVLeo.d.mts → with-text-input-DLoSCBrm.d.mts} +3 -3
  133. package/dist/{with-text-input-YeohVLeo.d.mts.map → with-text-input-DLoSCBrm.d.mts.map} +1 -1
  134. package/dist/wrap-measurer-registration-IV2HtcCd.d.mts +3106 -0
  135. package/dist/wrap-measurer-registration-IV2HtcCd.d.mts.map +1 -0
  136. package/dist/{wrapper-C70ATkVv.mjs → wrapper-CD29afOs.mjs} +59 -17
  137. package/dist/wrapper-CD29afOs.mjs.map +1 -0
  138. package/dist/{wrappers-BCUYITrY.mjs → wrappers-CInBJm44.mjs} +18 -8
  139. package/dist/wrappers-CInBJm44.mjs.map +1 -0
  140. package/dist/{yoga-adapter-BnZX1PAY.mjs → yoga-adapter-9uab5Qn-.mjs} +2 -2
  141. package/dist/{yoga-adapter-BnZX1PAY.mjs.map → yoga-adapter-9uab5Qn-.mjs.map} +1 -1
  142. package/dist/yoga-adapter-yqTl1aXK.mjs +2 -0
  143. package/package.json +59 -14
  144. package/dist/Text-Lq0dmj8-.mjs.map +0 -1
  145. package/dist/UPNG-Bo33r8rA.mjs +0 -3
  146. package/dist/UPNG-DosRPdF4.mjs.map +0 -1
  147. package/dist/__vite-browser-external-2447137e-D_JM6skp.mjs +0 -6
  148. package/dist/__vite-browser-external-2447137e-D_JM6skp.mjs.map +0 -1
  149. package/dist/ansi-yC4RyBNY.mjs +0 -22441
  150. package/dist/ansi-yC4RyBNY.mjs.map +0 -1
  151. package/dist/apng-CR08rIaH.mjs +0 -58
  152. package/dist/apng-CR08rIaH.mjs.map +0 -1
  153. package/dist/apng-DaHfVaVI.mjs +0 -3
  154. package/dist/assets/resvgjs.darwin-arm64-BtufyGW1.node +0 -0
  155. package/dist/assets/skia.darwin-arm64-DQs5sT6N.node +0 -0
  156. package/dist/backends-CUtan80W.mjs +0 -3
  157. package/dist/backends-DIVYzKqd.mjs +0 -1083
  158. package/dist/backends-DIVYzKqd.mjs.map +0 -1
  159. package/dist/bound-term-0sPrrzH1.d.mts.map +0 -1
  160. package/dist/canvas-1v7dPT-_.mjs +0 -3
  161. package/dist/canvas-CSuPOMNt.mjs +0 -1442
  162. package/dist/canvas-CSuPOMNt.mjs.map +0 -1
  163. package/dist/cli-dvo0r2fs.mjs +0 -4
  164. package/dist/compare-CQodSH4G.mjs +0 -376
  165. package/dist/compare-CQodSH4G.mjs.map +0 -1
  166. package/dist/compare-DHlcxEYA.mjs +0 -3
  167. package/dist/devtools-CJdt5H0X.mjs +0 -2
  168. package/dist/fonts-BFmhXDv7.mjs +0 -88
  169. package/dist/fonts-BFmhXDv7.mjs.map +0 -1
  170. package/dist/gif-C_AjaT9d.mjs +0 -188
  171. package/dist/gif-C_AjaT9d.mjs.map +0 -1
  172. package/dist/gif-DaC4XrxA.mjs +0 -3
  173. package/dist/gifenc-BOUT-KFB.mjs +0 -730
  174. package/dist/gifenc-BOUT-KFB.mjs.map +0 -1
  175. package/dist/image-C2Birh2x.mjs +0 -1252
  176. package/dist/image-C2Birh2x.mjs.map +0 -1
  177. package/dist/index-CSQf13CI.d.mts.map +0 -1
  178. package/dist/index-Cl9KKjQ_.d.mts.map +0 -1
  179. package/dist/key-mapping-CS-YD_cD.mjs +0 -132
  180. package/dist/key-mapping-CS-YD_cD.mjs.map +0 -1
  181. package/dist/key-mapping-Yn-Jgrij.mjs +0 -3
  182. package/dist/layout-signals-Cnw6xk8Q.mjs.map +0 -1
  183. package/dist/mouse-events-Dki3ISIp.mjs.map +0 -1
  184. package/dist/playwright-D5YiZcNS.mjs +0 -76397
  185. package/dist/playwright-D5YiZcNS.mjs.map +0 -1
  186. package/dist/png-codec-Dp84742B.mjs +0 -36
  187. package/dist/png-codec-Dp84742B.mjs.map +0 -1
  188. package/dist/png-codec-QwOtJ8Zs.mjs +0 -3
  189. package/dist/rasterizer-BRXrDdWx.mjs +0 -3
  190. package/dist/rasterizer-CpEhJvdR.mjs +0 -296
  191. package/dist/rasterizer-CpEhJvdR.mjs.map +0 -1
  192. package/dist/reconciler-DldIJB93.mjs.map +0 -1
  193. package/dist/render-string-DkQacASz.mjs.map +0 -1
  194. package/dist/resvg-js-DkOndZI3.mjs +0 -203
  195. package/dist/resvg-js-DkOndZI3.mjs.map +0 -1
  196. package/dist/schemes-JjNp4aSl.mjs +0 -2611
  197. package/dist/src-5w9QR6_8.mjs.map +0 -1
  198. package/dist/src-BNTToU7l.mjs.map +0 -1
  199. package/dist/src-BR4xNwdG.mjs.map +0 -1
  200. package/dist/src-DKp-_OFG.mjs.map +0 -1
  201. package/dist/src-bt8wSrfJ.mjs +0 -258
  202. package/dist/src-bt8wSrfJ.mjs.map +0 -1
  203. package/dist/src-e33Y6kNJ.mjs +0 -3
  204. package/dist/src-iDwu25UD.mjs +0 -1814
  205. package/dist/src-iDwu25UD.mjs.map +0 -1
  206. package/dist/svg-15lZZzxq.mjs +0 -486
  207. package/dist/svg-15lZZzxq.mjs.map +0 -1
  208. package/dist/svg-DY72a4HK.mjs +0 -3
  209. package/dist/term.mjs.map +0 -1
  210. package/dist/theme.mjs.map +0 -1
  211. package/dist/ui/display.d.mts +0 -35
  212. package/dist/ui/display.d.mts.map +0 -1
  213. package/dist/ui/display.mjs +0 -123
  214. package/dist/ui/display.mjs.map +0 -1
  215. package/dist/ui/input.d.mts +0 -184
  216. package/dist/ui/input.d.mts.map +0 -1
  217. package/dist/ui/input.mjs +0 -285
  218. package/dist/ui/input.mjs.map +0 -1
  219. package/dist/wrapper-C70ATkVv.mjs.map +0 -1
  220. package/dist/wrappers-BCUYITrY.mjs.map +0 -1
  221. package/dist/yoga-adapter-DxgsQ_gg.mjs +0 -2
  222. package/dist/zipBundle-3nqeDRtm.mjs +0 -3
  223. package/dist/zipBundle-VNAYFmqJ.mjs +0 -2003
  224. package/dist/zipBundle-VNAYFmqJ.mjs.map +0 -1
@@ -1,3 +0,0 @@
1
- import { i as init_compare, t as captureCrossRenderer } from "./compare-CQodSH4G.mjs";
2
- init_compare();
3
- export { captureCrossRenderer };
@@ -1,2 +0,0 @@
1
- import { t as autoConnectDevTools } from "./devtools-DcQjgyjL.mjs";
2
- export { autoConnectDevTools };
@@ -1,88 +0,0 @@
1
- import { n as __esmMin } from "./chunk-BSw8zbkd.mjs";
2
- import { existsSync } from "node:fs";
3
- import { dirname, join } from "node:path";
4
- import { fileURLToPath } from "node:url";
5
- //#region ../termless/src/render/fonts.ts
6
- /**
7
- * Bundled fallback fonts — the canonical termless font assets.
8
- *
9
- * Four OFL-licensed faces ship inside `@termless/core` under `assets/fonts`:
10
- *
11
- * - JetBrains Mono — primary monospace face (broad Latin + box-drawing)
12
- * - Noto Sans Symbols 2 — terminal symbol glyphs JetBrains Mono lacks
13
- * - Symbols Nerd Font — Nerd Font private-use icons (powerline, devicons,
14
- * the U+F0xx/U+E0xx glyphs TUIs like km use)
15
- * - Noto Emoji (mono) — emoji code points (📁 📋 📄, status emoji)
16
- *
17
- * Two render paths consume these:
18
- *
19
- * - The `@resvg/resvg-js` SVG→raster path (`./view/gif.ts`, `./view/apng.ts`,
20
- * `record --screenshot *.png`) — passes the font files to resvg's
21
- * `font.fontFiles` so emoji/symbol code points resolve instead of tofu.
22
- * - `@termless/ghostty`'s `@napi-rs/canvas` renderer — registers them
23
- * process-wide via `GlobalFonts.registerFromPath`.
24
- *
25
- * Both packages resolve the directory through this module so there is a
26
- * single bundled copy, owned by `@termless/core` (the foundational package).
27
- */
28
- /**
29
- * Resolve the bundled `assets/fonts` directory in both layouts:
30
- * - dev: `<pkg>/src/render/fonts.ts` → `<pkg>/assets/fonts`
31
- * - published: `<pkg>/dist/index.mjs` → `<pkg>/assets/fonts`
32
- *
33
- * In dev the file sits two levels deep (`src/render/`), in a published build
34
- * one level deep (`dist/`). We probe upward for the first ancestor that has
35
- * an `assets/fonts` child so both layouts resolve without a build-time guess.
36
- */
37
- function bundledFontsDir() {
38
- let here = dirname(fileURLToPath(import.meta.url));
39
- for (let i = 0; i < 4; i++) {
40
- const candidate = join(here, "assets", "fonts");
41
- if (existsSync(candidate)) return candidate;
42
- here = dirname(here);
43
- }
44
- return join(dirname(fileURLToPath(import.meta.url)), "..", "..", "assets", "fonts");
45
- }
46
- /**
47
- * Absolute paths of the bundled font files that actually exist on disk.
48
- * Missing files are skipped silently — a partial fallback chain still beats
49
- * a hard failure, and the bundled-font test pins the happy path.
50
- */
51
- function bundledFontFiles() {
52
- const dir = bundledFontsDir();
53
- const files = [];
54
- for (const { file } of BUNDLED_FONTS) {
55
- const path = join(dir, file);
56
- if (existsSync(path)) files.push(path);
57
- }
58
- return files;
59
- }
60
- var BUNDLED_PRIMARY_FAMILY, BUNDLED_SYMBOL_FAMILY, BUNDLED_NERD_FAMILY, BUNDLED_EMOJI_FAMILY, BUNDLED_FONTS;
61
- var init_fonts = __esmMin((() => {
62
- BUNDLED_PRIMARY_FAMILY = "TermlessMono";
63
- BUNDLED_SYMBOL_FAMILY = "TermlessSymbols";
64
- BUNDLED_NERD_FAMILY = "TermlessNerd";
65
- BUNDLED_EMOJI_FAMILY = "TermlessEmoji";
66
- BUNDLED_FONTS = [
67
- {
68
- file: "JetBrainsMono-Regular.ttf",
69
- family: BUNDLED_PRIMARY_FAMILY
70
- },
71
- {
72
- file: "NotoSansSymbols2-Regular.ttf",
73
- family: BUNDLED_SYMBOL_FAMILY
74
- },
75
- {
76
- file: "SymbolsNerdFontMono-Regular.ttf",
77
- family: BUNDLED_NERD_FAMILY
78
- },
79
- {
80
- file: "NotoEmoji-Regular.ttf",
81
- family: BUNDLED_EMOJI_FAMILY
82
- }
83
- ];
84
- }));
85
- //#endregion
86
- export { BUNDLED_SYMBOL_FAMILY as a, init_fonts as c, BUNDLED_PRIMARY_FAMILY as i, BUNDLED_FONTS as n, bundledFontFiles as o, BUNDLED_NERD_FAMILY as r, bundledFontsDir as s, BUNDLED_EMOJI_FAMILY as t };
87
-
88
- //# sourceMappingURL=fonts-BFmhXDv7.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"fonts-BFmhXDv7.mjs","names":[],"sources":["../../termless/src/render/fonts.ts"],"sourcesContent":["/**\n * Bundled fallback fonts — the canonical termless font assets.\n *\n * Four OFL-licensed faces ship inside `@termless/core` under `assets/fonts`:\n *\n * - JetBrains Mono — primary monospace face (broad Latin + box-drawing)\n * - Noto Sans Symbols 2 — terminal symbol glyphs JetBrains Mono lacks\n * - Symbols Nerd Font — Nerd Font private-use icons (powerline, devicons,\n * the U+F0xx/U+E0xx glyphs TUIs like km use)\n * - Noto Emoji (mono) — emoji code points (📁 📋 📄, status emoji)\n *\n * Two render paths consume these:\n *\n * - The `@resvg/resvg-js` SVG→raster path (`./view/gif.ts`, `./view/apng.ts`,\n * `record --screenshot *.png`) — passes the font files to resvg's\n * `font.fontFiles` so emoji/symbol code points resolve instead of tofu.\n * - `@termless/ghostty`'s `@napi-rs/canvas` renderer — registers them\n * process-wide via `GlobalFonts.registerFromPath`.\n *\n * Both packages resolve the directory through this module so there is a\n * single bundled copy, owned by `@termless/core` (the foundational package).\n */\n\nimport { dirname, join } from \"node:path\"\nimport { fileURLToPath } from \"node:url\"\nimport { existsSync } from \"node:fs\"\n\n/** Family names the bundled fonts are registered under (CSS `font-family`). */\nexport const BUNDLED_PRIMARY_FAMILY = \"TermlessMono\"\nexport const BUNDLED_SYMBOL_FAMILY = \"TermlessSymbols\"\nexport const BUNDLED_NERD_FAMILY = \"TermlessNerd\"\nexport const BUNDLED_EMOJI_FAMILY = \"TermlessEmoji\"\n\n/** One bundled font: a file name (relative to the fonts dir) + its family. */\nexport interface BundledFont {\n file: string\n family: string\n}\n\n/**\n * The bundled faces, in fallback order. The primary face is first; the\n * symbol + emoji faces follow so per-glyph fallback resolves in that order.\n */\nexport const BUNDLED_FONTS: readonly BundledFont[] = [\n { file: \"JetBrainsMono-Regular.ttf\", family: BUNDLED_PRIMARY_FAMILY },\n { file: \"NotoSansSymbols2-Regular.ttf\", family: BUNDLED_SYMBOL_FAMILY },\n { file: \"SymbolsNerdFontMono-Regular.ttf\", family: BUNDLED_NERD_FAMILY },\n { file: \"NotoEmoji-Regular.ttf\", family: BUNDLED_EMOJI_FAMILY },\n]\n\n/**\n * Resolve the bundled `assets/fonts` directory in both layouts:\n * - dev: `<pkg>/src/render/fonts.ts` → `<pkg>/assets/fonts`\n * - published: `<pkg>/dist/index.mjs` → `<pkg>/assets/fonts`\n *\n * In dev the file sits two levels deep (`src/render/`), in a published build\n * one level deep (`dist/`). We probe upward for the first ancestor that has\n * an `assets/fonts` child so both layouts resolve without a build-time guess.\n */\nexport function bundledFontsDir(): string {\n let here = dirname(fileURLToPath(import.meta.url))\n for (let i = 0; i < 4; i++) {\n const candidate = join(here, \"assets\", \"fonts\")\n if (existsSync(candidate)) return candidate\n here = dirname(here)\n }\n // Fall back to the dev layout (`src/render/` → two levels up) so callers\n // get a deterministic path even when the assets are absent.\n return join(dirname(fileURLToPath(import.meta.url)), \"..\", \"..\", \"assets\", \"fonts\")\n}\n\n/**\n * Absolute paths of the bundled font files that actually exist on disk.\n * Missing files are skipped silently — a partial fallback chain still beats\n * a hard failure, and the bundled-font test pins the happy path.\n */\nexport function bundledFontFiles(): string[] {\n const dir = bundledFontsDir()\n const files: string[] = []\n for (const { file } of BUNDLED_FONTS) {\n const path = join(dir, file)\n if (existsSync(path)) files.push(path)\n }\n return files\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA2DA,SAAgB,kBAA0B;CACxC,IAAI,OAAO,QAAQ,cAAc,OAAO,KAAK,IAAI,CAAC;AAClD,MAAK,IAAI,IAAI,GAAG,IAAI,GAAG,KAAK;EAC1B,MAAM,YAAY,KAAK,MAAM,UAAU,QAAQ;AAC/C,MAAI,WAAW,UAAU,CAAE,QAAO;AAClC,SAAO,QAAQ,KAAK;;AAItB,QAAO,KAAK,QAAQ,cAAc,OAAO,KAAK,IAAI,CAAC,EAAE,MAAM,MAAM,UAAU,QAAQ;;;;;;;AAQrF,SAAgB,mBAA6B;CAC3C,MAAM,MAAM,iBAAiB;CAC7B,MAAM,QAAkB,EAAE;AAC1B,MAAK,MAAM,EAAE,UAAU,eAAe;EACpC,MAAM,OAAO,KAAK,KAAK,KAAK;AAC5B,MAAI,WAAW,KAAK,CAAE,OAAM,KAAK,KAAK;;AAExC,QAAO;;;;AAvDI,0BAAyB;AACzB,yBAAwB;AACxB,uBAAsB;AACtB,wBAAuB;AAYvB,iBAAwC;EACnD;GAAE,MAAM;GAA6B,QAAQ;GAAwB;EACrE;GAAE,MAAM;GAAgC,QAAQ;GAAuB;EACvE;GAAE,MAAM;GAAmC,QAAQ;GAAqB;EACxE;GAAE,MAAM;GAAyB,QAAQ;GAAsB;EAChE"}
@@ -1,188 +0,0 @@
1
- import { n as __esmMin, o as __toESM } from "./chunk-BSw8zbkd.mjs";
2
- import { n as selectRasterizer, t as init_rasterizer } from "./rasterizer-CpEhJvdR.mjs";
3
- //#region ../termless/src/view/gif.ts
4
- async function loadGifenc() {
5
- if (gifencModule) return gifencModule;
6
- try {
7
- gifencModule = await import("./gifenc-BOUT-KFB.mjs").then((m) => /* @__PURE__ */ __toESM(m.default, 1));
8
- return gifencModule;
9
- } catch {
10
- throw new Error("createGif() requires gifenc. Install it:\n bun add gifenc");
11
- }
12
- }
13
- function svgHasChrome(svg) {
14
- return /windowBar|windowTitle|<rect[^>]*rx="\d+"/.test(svg);
15
- }
16
- function svgContentOffset(svg, scale) {
17
- const contentTransform = [...svg.matchAll(/<g[^>]*\btransform="translate\(\s*([\d.-]+)[,\s]+([\d.-]+)\s*\)"/g)].at(-1);
18
- if (!contentTransform) return {
19
- x: 0,
20
- y: 0
21
- };
22
- return {
23
- x: Math.round(Number(contentTransform[1]) * scale),
24
- y: Math.round(Number(contentTransform[2]) * scale)
25
- };
26
- }
27
- function compositeBitmap(base, overlay, offset) {
28
- const pixels = new Uint8Array(base.pixels);
29
- for (let y = 0; y < overlay.height; y++) {
30
- const dy = y + offset.y;
31
- if (dy < 0 || dy >= base.height) continue;
32
- for (let x = 0; x < overlay.width; x++) {
33
- const dx = x + offset.x;
34
- if (dx < 0 || dx >= base.width) continue;
35
- const si = (y * overlay.width + x) * 4;
36
- const di = (dy * base.width + dx) * 4;
37
- const srcAlpha = overlay.pixels[si + 3] / 255;
38
- if (srcAlpha <= 0) continue;
39
- if (srcAlpha >= 1) {
40
- pixels[di] = overlay.pixels[si];
41
- pixels[di + 1] = overlay.pixels[si + 1];
42
- pixels[di + 2] = overlay.pixels[si + 2];
43
- pixels[di + 3] = overlay.pixels[si + 3];
44
- continue;
45
- }
46
- const dstAlpha = pixels[di + 3] / 255;
47
- const outAlpha = srcAlpha + dstAlpha * (1 - srcAlpha);
48
- if (outAlpha <= 0) continue;
49
- const dstWeight = dstAlpha * (1 - srcAlpha) / outAlpha;
50
- const srcWeight = srcAlpha / outAlpha;
51
- pixels[di] = Math.round(overlay.pixels[si] * srcWeight + pixels[di] * dstWeight);
52
- pixels[di + 1] = Math.round(overlay.pixels[si + 1] * srcWeight + pixels[di + 1] * dstWeight);
53
- pixels[di + 2] = Math.round(overlay.pixels[si + 2] * srcWeight + pixels[di + 2] * dstWeight);
54
- pixels[di + 3] = Math.round(outAlpha * 255);
55
- }
56
- }
57
- return {
58
- ...base,
59
- pixels
60
- };
61
- }
62
- /**
63
- * Encode animation frames as an animated GIF.
64
- *
65
- * Each SVG frame is rasterized to RGBA pixels via the selected renderer
66
- * (`options.renderer`, default `auto`), then quantized to 256 colors and
67
- * written to a GIF stream via gifenc.
68
- *
69
- * @param frames - SVG frames with durations
70
- * @param options - Animation options plus optional `scale` and `renderer`
71
- * @returns GIF file as Uint8Array
72
- */
73
- async function createGif(frames, options) {
74
- if (frames.length === 0) throw new Error("createGif requires at least one frame");
75
- const [{ GIFEncoder, quantize, applyPalette }, rasterizer] = await Promise.all([loadGifenc(), selectRasterizer(options?.renderer ?? "auto")]);
76
- const defaultDuration = options?.defaultDuration ?? 100;
77
- const loop = options?.loop ?? 0;
78
- const scale = options?.scale ?? 2;
79
- const forceSvg = options?.forceSvg === true;
80
- const gif = GIFEncoder();
81
- const rasterize = async (frame) => {
82
- if (forceSvg || !frame.snapshot || !rasterizer.rasterizeCells) return rasterizer.rasterize(frame.svg, scale);
83
- const cells = await rasterizer.rasterizeCells(frame.snapshot, scale);
84
- if (!svgHasChrome(frame.svg)) return cells;
85
- return compositeBitmap(await rasterizer.rasterize(frame.svg, scale), cells, svgContentOffset(frame.svg, scale));
86
- };
87
- try {
88
- const sampleIdx = Math.floor(frames.length / 2);
89
- const sample = await rasterize(frames[sampleIdx]);
90
- const palette = quantize(sample.pixels, 255);
91
- const TRANSPARENT_IDX = 255;
92
- let prevIndexed = null;
93
- for (let i = 0; i < frames.length; i++) {
94
- const frame = frames[i];
95
- const duration = frame.duration || defaultDuration;
96
- const { pixels: rgba, width, height } = i === sampleIdx ? sample : await rasterize(frame);
97
- const indexed = applyPalette(rgba, palette);
98
- const canDiff = prevIndexed !== null && prevIndexed.length === indexed.length;
99
- let frameData = indexed;
100
- if (canDiff) {
101
- const delta = new Uint8Array(indexed.length);
102
- for (let p = 0; p < indexed.length; p++) delta[p] = indexed[p] === prevIndexed[p] ? TRANSPARENT_IDX : indexed[p];
103
- frameData = delta;
104
- }
105
- gif.writeFrame(frameData, width, height, {
106
- palette: i === 0 ? palette : void 0,
107
- delay: duration,
108
- repeat: i === 0 ? loop === 0 ? 0 : loop : void 0,
109
- transparent: canDiff,
110
- transparentIndex: TRANSPARENT_IDX,
111
- dispose: 1
112
- });
113
- if ((i & 3) === 3) await new Promise((r) => setImmediate(r));
114
- prevIndexed = indexed;
115
- }
116
- } finally {
117
- await rasterizer.dispose?.();
118
- }
119
- gif.finish();
120
- return gif.bytesView();
121
- }
122
- /**
123
- * Encode already-rasterized PNG frames as an animated GIF.
124
- *
125
- * Unlike {@link createGif}, the frames are pre-rendered PNGs — no SVG round-
126
- * trip, no `@resvg/resvg-js`. Used by the cross-backend compositor
127
- * (`../tape/compare-canvas.ts`), whose frames are composed PNGs.
128
- *
129
- * All frames are expected to share dimensions (the compositor guarantees this
130
- * by time-syncing the panel layout); a mismatched frame is letterboxed onto
131
- * the first frame's canvas size.
132
- */
133
- async function createGifFromPngs(frames, options) {
134
- if (frames.length === 0) throw new Error("createGifFromPngs requires at least one frame");
135
- const { GIFEncoder, quantize, applyPalette } = await loadGifenc();
136
- const defaultDuration = options?.defaultDuration ?? 100;
137
- const loop = options?.loop ?? 0;
138
- const decode = options?.decodePng ?? await (async () => {
139
- const { decodePngRgba } = await import("./png-codec-QwOtJ8Zs.mjs");
140
- return decodePngRgba;
141
- })();
142
- const gif = GIFEncoder();
143
- let baseW = 0;
144
- let baseH = 0;
145
- for (let i = 0; i < frames.length; i++) {
146
- const frame = frames[i];
147
- const decoded = decode(frame.png);
148
- if (i === 0) {
149
- baseW = decoded.width;
150
- baseH = decoded.height;
151
- }
152
- let rgba = decoded.data;
153
- let width = decoded.width;
154
- let height = decoded.height;
155
- if (width !== baseW || height !== baseH) {
156
- const padded = new Uint8Array(baseW * baseH * 4);
157
- for (let y = 0; y < Math.min(height, baseH); y++) for (let x = 0; x < Math.min(width, baseW); x++) {
158
- const si = (y * width + x) * 4;
159
- const di = (y * baseW + x) * 4;
160
- padded[di] = rgba[si];
161
- padded[di + 1] = rgba[si + 1];
162
- padded[di + 2] = rgba[si + 2];
163
- padded[di + 3] = rgba[si + 3];
164
- }
165
- rgba = padded;
166
- width = baseW;
167
- height = baseH;
168
- }
169
- const palette = quantize(rgba, 256);
170
- const indexed = applyPalette(rgba, palette);
171
- gif.writeFrame(indexed, width, height, {
172
- palette,
173
- delay: frame.duration || defaultDuration,
174
- repeat: i === 0 ? loop === 0 ? 0 : loop : void 0
175
- });
176
- }
177
- gif.finish();
178
- return gif.bytesView();
179
- }
180
- var gifencModule;
181
- var init_gif = __esmMin((() => {
182
- init_rasterizer();
183
- gifencModule = null;
184
- }));
185
- //#endregion
186
- export { createGifFromPngs as n, init_gif as r, createGif as t };
187
-
188
- //# sourceMappingURL=gif-C_AjaT9d.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"gif-C_AjaT9d.mjs","names":[],"sources":["../../termless/src/view/gif.ts"],"sourcesContent":["/**\n * Animated GIF encoder for termless.\n *\n * Converts SVG frames to an animated GIF using gifenc (pure JS, no binary deps)\n * for GIF encoding. SVG → pixel rasterization goes through the **renderer**\n * (`./rasterizer.ts`): `canvas` (`@napi-rs/canvas`, high fidelity) when its\n * native binding loads, `resvg` (`@resvg/resvg-js`) as the cross-platform\n * fallback. The renderer is *not* hardwired — a default `out.gif` gets\n * `canvas` fidelity when the binding is available.\n *\n * `gifenc` is an optional/lazy-loaded dependency — throws a clear error if\n * missing.\n */\n\n// Module declarations live in ./gifenc.d.ts (picked up via tsconfig `include` glob).\nimport type { AnimationFrame, AnimationOptions } from \"./animation-types.ts\"\nimport { selectRasterizer, type RasterBitmap, type RendererKind } from \"./rasterizer.ts\"\n\n// Lazy-cached imports\nlet gifencModule: typeof import(\"gifenc\") | null = null\n\nasync function loadGifenc() {\n if (gifencModule) return gifencModule\n try {\n gifencModule = await import(\"gifenc\")\n return gifencModule\n } catch {\n throw new Error(\"createGif() requires gifenc. Install it:\\n bun add gifenc\")\n }\n}\n\nfunction svgHasChrome(svg: string): boolean {\n return /windowBar|windowTitle|<rect[^>]*rx=\"\\d+\"/.test(svg)\n}\n\nfunction svgContentOffset(svg: string, scale: number): { x: number; y: number } {\n const transforms = [...svg.matchAll(/<g[^>]*\\btransform=\"translate\\(\\s*([\\d.-]+)[,\\s]+([\\d.-]+)\\s*\\)\"/g)]\n const contentTransform = transforms.at(-1)\n if (!contentTransform) return { x: 0, y: 0 }\n return {\n x: Math.round(Number(contentTransform[1]) * scale),\n y: Math.round(Number(contentTransform[2]) * scale),\n }\n}\n\nfunction compositeBitmap(base: RasterBitmap, overlay: RasterBitmap, offset: { x: number; y: number }): RasterBitmap {\n const pixels = new Uint8Array(base.pixels)\n for (let y = 0; y < overlay.height; y++) {\n const dy = y + offset.y\n if (dy < 0 || dy >= base.height) continue\n for (let x = 0; x < overlay.width; x++) {\n const dx = x + offset.x\n if (dx < 0 || dx >= base.width) continue\n\n const si = (y * overlay.width + x) * 4\n const di = (dy * base.width + dx) * 4\n const srcAlpha = overlay.pixels[si + 3]! / 255\n if (srcAlpha <= 0) continue\n if (srcAlpha >= 1) {\n pixels[di] = overlay.pixels[si]!\n pixels[di + 1] = overlay.pixels[si + 1]!\n pixels[di + 2] = overlay.pixels[si + 2]!\n pixels[di + 3] = overlay.pixels[si + 3]!\n continue\n }\n\n const dstAlpha = pixels[di + 3]! / 255\n const outAlpha = srcAlpha + dstAlpha * (1 - srcAlpha)\n if (outAlpha <= 0) continue\n\n const dstWeight = (dstAlpha * (1 - srcAlpha)) / outAlpha\n const srcWeight = srcAlpha / outAlpha\n pixels[di] = Math.round(overlay.pixels[si]! * srcWeight + pixels[di]! * dstWeight)\n pixels[di + 1] = Math.round(overlay.pixels[si + 1]! * srcWeight + pixels[di + 1]! * dstWeight)\n pixels[di + 2] = Math.round(overlay.pixels[si + 2]! * srcWeight + pixels[di + 2]! * dstWeight)\n pixels[di + 3] = Math.round(outAlpha * 255)\n }\n }\n return { ...base, pixels }\n}\n\n/**\n * Encode animation frames as an animated GIF.\n *\n * Each SVG frame is rasterized to RGBA pixels via the selected renderer\n * (`options.renderer`, default `auto`), then quantized to 256 colors and\n * written to a GIF stream via gifenc.\n *\n * @param frames - SVG frames with durations\n * @param options - Animation options plus optional `scale` and `renderer`\n * @returns GIF file as Uint8Array\n */\nexport async function createGif(\n frames: AnimationFrame[],\n options?: AnimationOptions & { scale?: number; renderer?: RendererKind; forceSvg?: boolean },\n): Promise<Uint8Array> {\n if (frames.length === 0) {\n throw new Error(\"createGif requires at least one frame\")\n }\n\n const [{ GIFEncoder, quantize, applyPalette }, rasterizer] = await Promise.all([\n loadGifenc(),\n selectRasterizer(options?.renderer ?? \"auto\"),\n ])\n\n const defaultDuration = options?.defaultDuration ?? 100\n const loop = options?.loop ?? 0\n const scale = options?.scale ?? 2\n const forceSvg = options?.forceSvg === true\n\n const gif = GIFEncoder()\n\n // Cell-native path: a renderer that exposes `rasterizeCells` (swash) skips\n // the SVG round-trip when the frame carries a snapshot — that is what makes\n // color emoji and exact glyph coverage survive into the GIF. If the SVG\n // also carries chrome, rasterize the chrome SVG and overwrite only the\n // terminal content rectangle with the cell-native bitmap.\n const rasterize = async (frame: AnimationFrame) => {\n if (forceSvg || !frame.snapshot || !rasterizer.rasterizeCells) {\n return rasterizer.rasterize(frame.svg, scale)\n }\n\n const cells = await rasterizer.rasterizeCells(frame.snapshot, scale)\n if (!svgHasChrome(frame.svg)) return cells\n\n const chrome = await rasterizer.rasterize(frame.svg, scale)\n return compositeBitmap(chrome, cells, svgContentOffset(frame.svg, scale))\n }\n\n // Shared global palette. A terminal recording's colour set barely changes\n // frame to frame (theme + ANSI + anti-alias blends), so quantizing a fresh\n // palette per frame — and re-embedding it in every frame — is pure bloat.\n // Quantize ONCE from a representative content-bearing frame and reuse it as\n // the GIF's global colour table. 255 colours, not 256: index 255 is\n // reserved as the inter-frame transparency marker (below).\n //\n // The whole batch runs inside try/finally so the `browser` renderer's\n // headless-Chromium instance is released even if encoding throws.\n try {\n const sampleIdx = Math.floor(frames.length / 2)\n const sample = await rasterize(frames[sampleIdx]!)\n const palette = quantize(sample.pixels, 255)\n const TRANSPARENT_IDX = 255\n\n // Inter-frame diffing. Successive terminal frames differ in only a handful\n // of cells, so after frame 0 each frame is written as a *delta*: pixels\n // unchanged from the previous frame become the transparent index, and the\n // frame is composited over its predecessor (`dispose: 1` — do not dispose).\n // Long runs of the transparent index compress near-free under LZW — the\n // dominant GIF-size win for a recording.\n let prevIndexed: Uint8Array | null = null\n\n for (let i = 0; i < frames.length; i++) {\n const frame = frames[i]!\n const duration = frame.duration || defaultDuration\n\n const { pixels: rgba, width, height } = i === sampleIdx ? sample : await rasterize(frame)\n const indexed = applyPalette(rgba, palette)\n\n // Delta-encode against the previous frame when dimensions match.\n const canDiff = prevIndexed !== null && prevIndexed.length === indexed.length\n let frameData = indexed\n if (canDiff) {\n const delta = new Uint8Array(indexed.length)\n for (let p = 0; p < indexed.length; p++) {\n delta[p] = indexed[p] === prevIndexed![p] ? TRANSPARENT_IDX : indexed[p]!\n }\n frameData = delta\n }\n\n gif.writeFrame(frameData, width, height, {\n // Only the first frame carries the palette — it becomes the global\n // colour table; later frames reference it (no per-frame local table).\n palette: i === 0 ? palette : undefined,\n delay: duration,\n repeat: i === 0 ? (loop === 0 ? 0 : loop) : undefined,\n // Frames after the first are deltas: transparent pixels show the\n // composited prior frame through. `dispose: 1` keeps each frame in\n // place so the next delta lands on top of it.\n transparent: canDiff,\n transparentIndex: TRANSPARENT_IDX,\n dispose: 1,\n })\n\n // Yield to the event loop every frame so external progress UIs\n // (spinners, ProgressBar) can tick. `gif.writeFrame` is CPU-bound\n // (LZW encoding); without a yield the encoding loop monopolises\n // the loop for the entire run and any silvery/react Spinner timer\n // in the host process freezes mid-animation.\n if ((i & 3) === 3) await new Promise<void>((r) => setImmediate(r))\n\n // Compare the NEXT frame against this frame's full (un-delta'd) content.\n prevIndexed = indexed\n }\n } finally {\n // Release the headless-Chromium instance the `browser` renderer holds.\n await rasterizer.dispose?.()\n }\n\n gif.finish()\n return gif.bytesView()\n}\n\n/** One PNG-backed animation frame: pre-rasterized bytes + a display duration. */\nexport interface PngFrame {\n /** PNG bytes of this frame. */\n png: Uint8Array\n /** Display duration in milliseconds. */\n duration: number\n}\n\n/**\n * Encode already-rasterized PNG frames as an animated GIF.\n *\n * Unlike {@link createGif}, the frames are pre-rendered PNGs — no SVG round-\n * trip, no `@resvg/resvg-js`. Used by the cross-backend compositor\n * (`../tape/compare-canvas.ts`), whose frames are composed PNGs.\n *\n * All frames are expected to share dimensions (the compositor guarantees this\n * by time-syncing the panel layout); a mismatched frame is letterboxed onto\n * the first frame's canvas size.\n */\nexport async function createGifFromPngs(\n frames: PngFrame[],\n options?: AnimationOptions & { decodePng?: (png: Uint8Array) => { width: number; height: number; data: Uint8Array } },\n): Promise<Uint8Array> {\n if (frames.length === 0) {\n throw new Error(\"createGifFromPngs requires at least one frame\")\n }\n const { GIFEncoder, quantize, applyPalette } = await loadGifenc()\n const defaultDuration = options?.defaultDuration ?? 100\n const loop = options?.loop ?? 0\n\n // Decoder: caller-supplied (the compositor passes its upng codec) or upng.\n const decode =\n options?.decodePng ??\n (await (async () => {\n const { decodePngRgba } = await import(\"../recording/tape/png-codec.ts\")\n return decodePngRgba\n })())\n\n const gif = GIFEncoder()\n let baseW = 0\n let baseH = 0\n\n for (let i = 0; i < frames.length; i++) {\n const frame = frames[i]!\n const decoded = decode(frame.png)\n if (i === 0) {\n baseW = decoded.width\n baseH = decoded.height\n }\n let rgba = decoded.data\n let width = decoded.width\n let height = decoded.height\n if (width !== baseW || height !== baseH) {\n // Letterbox onto the base canvas (top-left aligned).\n const padded = new Uint8Array(baseW * baseH * 4)\n for (let y = 0; y < Math.min(height, baseH); y++) {\n for (let x = 0; x < Math.min(width, baseW); x++) {\n const si = (y * width + x) * 4\n const di = (y * baseW + x) * 4\n padded[di] = rgba[si]!\n padded[di + 1] = rgba[si + 1]!\n padded[di + 2] = rgba[si + 2]!\n padded[di + 3] = rgba[si + 3]!\n }\n }\n rgba = padded\n width = baseW\n height = baseH\n }\n const palette = quantize(rgba, 256)\n const indexed = applyPalette(rgba, palette)\n gif.writeFrame(indexed, width, height, {\n palette,\n delay: frame.duration || defaultDuration,\n repeat: i === 0 ? (loop === 0 ? 0 : loop) : undefined,\n })\n }\n\n gif.finish()\n return gif.bytesView()\n}\n"],"mappings":"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"}
@@ -1,3 +0,0 @@
1
- import { r as init_gif, t as createGif } from "./gif-C_AjaT9d.mjs";
2
- init_gif();
3
- export { createGif };